From f4bd80a2dcc200d939292c877b3fdadb7f3a261e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stephan=20A=C3=9Fmus?= Date: Sun, 10 Sep 2006 22:31:09 +0000 Subject: [PATCH] * when loading an icon via drag&drop, the file will be remembered for saving later * added "Clean Up" feature to "Path" menu * added "Freeze Transformation" to "Shape" menu (will apply the current shape transformation onto the path and reset the shape transformation to identity) * small cleanup in ShapeListView * implemented zooming in CanvasView * added context menu while editing a path * implemented undo/redo for transforming points (press T or use context menu) * added "Split Points" feature (path editing context menu), it will make two points from one control point * improved selecting path points with selection rect * improved SVG import for zuMis BeOS icons (more precise scale) git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@18800 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- src/apps/icon-o-matic/CanvasView.cpp | 144 +++++++++++++++- src/apps/icon-o-matic/CanvasView.h | 18 +- src/apps/icon-o-matic/Icon-O-Matic.rdef | 71 ++++++++ src/apps/icon-o-matic/IconEditorApp.cpp | 23 ++- src/apps/icon-o-matic/Jamfile | 6 + src/apps/icon-o-matic/MainWindow.cpp | 19 ++- .../generic/gui/stateview/Manipulator.cpp | 7 + .../generic/gui/stateview/Manipulator.h | 2 + .../stateview/MultipleManipulatorState.cpp | 20 ++- .../gui/stateview/MultipleManipulatorState.h | 2 + .../generic/gui/stateview/ViewState.cpp | 2 +- .../generic/gui/stateview/ViewState.h | 1 - src/apps/icon-o-matic/gui/PathListView.cpp | 17 ++ src/apps/icon-o-matic/gui/PathListView.h | 1 + src/apps/icon-o-matic/gui/ShapeListView.cpp | 47 ++++-- src/apps/icon-o-matic/gui/ShapeListView.h | 3 + .../import_export/svg/DocumentBuilder.cpp | 16 +- .../icon-o-matic/shape/PathManipulator.cpp | 95 +++++++++-- src/apps/icon-o-matic/shape/PathManipulator.h | 2 + .../shape/commands/CleanUpPathCommand.cpp | 52 ++++++ .../shape/commands/CleanUpPathCommand.h | 29 ++++ .../commands/FreezeTransformationCommand.cpp | 152 +++++++++++++++++ .../commands/FreezeTransformationCommand.h | 40 +++++ .../shape/commands/ReversePathCommand.cpp | 8 + .../shape/commands/ReversePathCommand.h | 8 + .../shape/commands/SplitPointsCommand.cpp | 154 ++++++++++++++++++ .../shape/commands/SplitPointsCommand.h | 39 +++++ .../shape/commands/TransformPointsCommand.cpp | 122 ++++++++++++++ .../shape/commands/TransformPointsCommand.h | 63 +++++++ .../transformable/TransformPointsBox.cpp | 30 ++-- 30 files changed, 1139 insertions(+), 54 deletions(-) create mode 100644 src/apps/icon-o-matic/Icon-O-Matic.rdef create mode 100644 src/apps/icon-o-matic/shape/commands/CleanUpPathCommand.cpp create mode 100644 src/apps/icon-o-matic/shape/commands/CleanUpPathCommand.h create mode 100644 src/apps/icon-o-matic/shape/commands/FreezeTransformationCommand.cpp create mode 100644 src/apps/icon-o-matic/shape/commands/FreezeTransformationCommand.h create mode 100644 src/apps/icon-o-matic/shape/commands/SplitPointsCommand.cpp create mode 100644 src/apps/icon-o-matic/shape/commands/SplitPointsCommand.h create mode 100644 src/apps/icon-o-matic/shape/commands/TransformPointsCommand.cpp create mode 100644 src/apps/icon-o-matic/shape/commands/TransformPointsCommand.h diff --git a/src/apps/icon-o-matic/CanvasView.cpp b/src/apps/icon-o-matic/CanvasView.cpp index 2b603ee226..970dae8be0 100644 --- a/src/apps/icon-o-matic/CanvasView.cpp +++ b/src/apps/icon-o-matic/CanvasView.cpp @@ -28,8 +28,8 @@ CanvasView::CanvasView(BRect frame) fRenderer(new IconRenderer(fBitmap)), fDirtyIconArea(fBitmap->Bounds()), - fCanvasOrigin(50.0, 50.0), - fZoomLevel(8.0), + fCanvasOrigin(0.0, 0.0), + fZoomLevel(1.0), fMouseFilterMode(SNAPPING_OFF), @@ -68,6 +68,8 @@ CanvasView::AttachedToWindow() SetHighColor(kStripesLow); _AllocBackBitmap(Bounds().Width(), Bounds().Height()); + + _SetZoom(8.0); } // FrameResized @@ -140,6 +142,25 @@ CanvasView::MouseMoved(BPoint where, uint32 transit, // #pragma mark - +// ScrollOffsetChanged +void +CanvasView::ScrollOffsetChanged(BPoint oldOffset, BPoint newOffset) +{ + BPoint offset = newOffset - oldOffset; + ScrollBy(offset.x, offset.y); + + MouseMoved(fMouseInfo.position + offset, fMouseInfo.transit, NULL); +} + +// VisibleSizeChanged +void +CanvasView::VisibleSizeChanged(float oldWidth, float oldHeight, + float newWidth, float newHeight) +{ +} + +// #pragma mark - + // AreaInvalidated void CanvasView::AreaInvalidated(const BRect& area) @@ -240,6 +261,13 @@ CanvasView::_HandleKeyDown(uint32 key, uint32 modifiers) CommandStack()->Undo(); break; + case '+': + _SetZoom(_NextZoomInLevel(fZoomLevel)); + break; + case '-': + _SetZoom(_NextZoomOutLevel(fZoomLevel)); + break; + default: return StateView::_HandleKeyDown(key, modifiers); } @@ -446,3 +474,115 @@ CanvasView::_MakeBackground() } } +// #pragma mark - + +// _NextZoomInLevel +double +CanvasView::_NextZoomInLevel(double zoom) const +{ + if (zoom < 1) + return 1; + if (zoom < 1.5) + return 1.5; + if (zoom < 2) + return 2; + if (zoom < 3) + return 3; + if (zoom < 4) + return 4; + if (zoom < 6) + return 6; + if (zoom < 8) + return 8; + if (zoom < 16) + return 16; + if (zoom < 32) + return 32; + return 64; +} + +// _NextZoomOutLevel +double +CanvasView::_NextZoomOutLevel(double zoom) const +{ + if (zoom > 32) + return 32; + if (zoom > 16) + return 16; + if (zoom > 8) + return 8; + if (zoom > 6) + return 6; + if (zoom > 4) + return 4; + if (zoom > 3) + return 3; + if (zoom > 2) + return 2; + if (zoom > 1.5) + return 1.5; + return 1; +} + +// _SetZoom +void +CanvasView::_SetZoom(double zoomLevel) +{ + if (fZoomLevel == zoomLevel) + return; + + // zoom into mouse position, or into center of view + BPoint anchor = MouseInfo()->position; + BRect bounds(Bounds()); + if (!bounds.Contains(anchor)) { + bounds = _CanvasRect(); + anchor.x = (bounds.left + bounds.right) / 2.0; + anchor.y = (bounds.top + bounds.bottom) / 2.0; + } +printf("anchor: %.2f, %.2f\n", anchor.x, anchor.y); + + BPoint offset; + if (fZoomLevel < zoomLevel) { + offset.x = anchor.x * (zoomLevel / fZoomLevel) - anchor.x; + offset.y = anchor.y * (zoomLevel / fZoomLevel) - anchor.y; + } else { + offset.x = -anchor.x * (zoomLevel / fZoomLevel); + offset.y = -anchor.y * (zoomLevel / fZoomLevel); + } + + fZoomLevel = zoomLevel; + SetDataRect(_LayoutCanvas()); + +printf("offset: %.2f, %.2f\n", offset.x, offset.y); + + SetScrollOffset(ScrollOffset() + offset); + + Invalidate(); +} + +// _LayoutCanvas +BRect +CanvasView::_LayoutCanvas() +{ + if (!fBitmap) + return BRect(0, 0, -1, -1); + + // size of zoomed bitmap + BRect r(fBitmap->Bounds()); + r.OffsetTo(0, 0); + r.right = floorf((r.Width() + 1) * fZoomLevel + 0.5) - 1; + r.bottom = floorf((r.Height() + 1) * fZoomLevel + 0.5) - 1; + + // TODO: ask manipulators to extend size + + // left top of canvas within empty area + fCanvasOrigin.x = floorf(r.Width() * 0.25); + fCanvasOrigin.y = floorf(r.Height() * 0.25); + + // resize for empty area around bitmap + r.right += r.Width() * 0.5; + r.bottom += r.Height() * 0.5; + + return r; +} + diff --git a/src/apps/icon-o-matic/CanvasView.h b/src/apps/icon-o-matic/CanvasView.h index 9766f641ac..edc27aa978 100644 --- a/src/apps/icon-o-matic/CanvasView.h +++ b/src/apps/icon-o-matic/CanvasView.h @@ -10,6 +10,7 @@ #define CANVAS_VIEW_H #include "Icon.h" +#include "Scrollable.h" #include "StateView.h" class BBitmap; @@ -23,6 +24,7 @@ enum { }; class CanvasView : public StateView, + public Scrollable, public IconListener { public: CanvasView(BRect frame); @@ -37,7 +39,16 @@ class CanvasView : public StateView, virtual void MouseMoved(BPoint where, uint32 transit, const BMessage* dragMessage); + // Scrollable interface + protected: + virtual void ScrollOffsetChanged(BPoint oldOffset, + BPoint newOffset); + virtual void VisibleSizeChanged(float oldWidth, + float oldHeight, + float newWidth, + float newHeight); // IconListener interface + public: virtual void AreaInvalidated(const BRect& area); // CanvasView @@ -74,6 +85,11 @@ class CanvasView : public StateView, void _MakeBackground(); private: + double _NextZoomInLevel(double zoom) const; + double _NextZoomOutLevel(double zoom) const; + void _SetZoom(double zoomLevel); + BRect _LayoutCanvas(); + BBitmap* fBitmap; BBitmap* fBackground; @@ -82,7 +98,7 @@ class CanvasView : public StateView, BRect fDirtyIconArea; BPoint fCanvasOrigin; - float fZoomLevel; + double fZoomLevel; uint32 fMouseFilterMode; diff --git a/src/apps/icon-o-matic/Icon-O-Matic.rdef b/src/apps/icon-o-matic/Icon-O-Matic.rdef new file mode 100644 index 0000000000..a51da69a2a --- /dev/null +++ b/src/apps/icon-o-matic/Icon-O-Matic.rdef @@ -0,0 +1,71 @@ +/* + * Icon-O-Matic.rdef + */ + +resource app_signature "application/x-vnd.haiku-icon_o_matic"; + +resource app_version { + major = 1, + middle = 0, + minor = 0, + + /* 0 = development 1 = alpha 2 = beta + 3 = gamma 4 = golden master 5 = final */ + variety = 2, + + internal = 0, + + short_info = "Icon-O-Matic", + long_info = "Icon-O-Matic 1.0.0 ©2006 Haiku" +}; + +resource app_flags B_SINGLE_LAUNCH; + +//resource file_types message { +// "types" = "application/x-haiku_icon", +//}; + +resource(101, "BEOS:ICON") #'RAWT' array { + $"6E6369660E050102000603399E0F3D9C0ABF82B23B84A94B88504910C900A5B1" + $"FFBCEAF1FFFFB3B8FF020106023E49240000000000003CAAAA4940004A8000FF" + $"C0D5FF7C896EFF040192020006023B8E380000000000004000004AAA003A0000" + $"002B30A0FFCBDCFA038089D80200060237889D389554BBFC4A3AB9D048DADE4A" + $"322000FFF9BAFFFFC10402000602B5B574397997BC15F4B839E3489DF94B8820" + $"00C7E3FFFF392FFF0200060237A0CC393C5ABC1AC23A5C164A39B94B1E5400FD" + $"B9B9FFCE3232020006023D4D340000000000004000004A50000000000097A3BA" + $"FFF8FBFF020006023C08200000000000004000004A4000000000FF7E94B4005F" + $"6C9302000602B507E13A82E2BAD599B56BB44A7652479FE4002B2D3DFE444C6D" + $"02000603B2F679BA14D43A7FB6B38E9E474F5546D05A00F0CD9B81C0995DCFF0" + $"D8B502000602AAB1FB3A081FBE8A26AF5E794C4014448D43FFFDDCAB00DBAB5F" + $"140606AE0BB40BC14B33C5ADB75DC371BDEFC805C13ECA02CA28BF80C118BB1E" + $"C51BBD3EBF07BA063AB8BA060CAEAABAB40BC14B33C5ADB75DC371BDEFC805C1" + $"3ECA02C4E04F41C507374B3A4945C33CC6D1C36FCA28BF80C118BB1EC51BBD3E" + $"BF07BA063AB8BA0605AE02B57D43B9B9C5EDB7BB49BBB756BD75CB34CA8EC3AF" + $"40340609AEAA02B57D43B9B9C5EDB7BB49BBB756BD75CB34C6F0C5C24E4F514B" + $"C9BBC428CA8EC3AF40340A093B5E3D60BFCDCB3C4560C516C7EF604B5B485D4A" + $"44560A045A475E445A4257450A06C4E04F41C507374B3A4945C33CC6D1C36F0A" + $"04C6F0C5C24E4F514BC9BBC4280A062A452B4D3251364D35452F420A06245225" + $"5A2B5E315A31522A4E0A053153315B375F3C5B3C530606B20831245356295625" + $"562D532E3126290A063124B8BAB5B2B8BAB779312EB677B6ECB67CB63C0804BA" + $"28B4D33027302BBA28B8580A043324B969B5BA4E2751240A04B969B5BAB969B7" + $"714E2B4E270A04B969B771332E512E4E2B0003C6E8B4D3C6E8B4D3C690B51750" + $"2950B59E50B78DC6E8B858C690B814C6E8B8580604EE532456295625562D532E" + $"5029502D50250604EE532755295528552A532B5229522A5228120A0302040500" + $"0A0001021001178400040A020103000A050107000A0001001001178400040A01" + $"0101000A000108123E7578BF27AD3F27AD3E7578C831624850E201178400040A" + $"060108023E7578BF27AD3F27AD3E7578C831624850E20A070109023E7578BF27" + $"AD3F27AD3E7578C831624850E20A08010A023E7578BF27AD3F27AD3E7578C831" + $"624850E20A040106000A00030B0D11123ED413BED4133ED4133ED41347F4A24A" + $"588901178400040A0C010C023ED413BED4133ED4133ED41347F4A24A58890A09" + $"010E023ED413BED4133ED4133ED41347F4A24A58890A0A010F023ED413BED413" + $"3ED4133ED41347F4A24A58890A0B0110023ED413BED4133ED4133ED41347F4A2" + $"4A58890A0D0112023ED413BED4133ED4133ED41347F4A24A58890A0001130A3E" + $"D413BED4133ED4133ED41347F4A24A588915FF" +}; + + +//resource large_icon array { +//}; +// +//resource mini_icon array { +//}; diff --git a/src/apps/icon-o-matic/IconEditorApp.cpp b/src/apps/icon-o-matic/IconEditorApp.cpp index 261894726d..502ab7a929 100644 --- a/src/apps/icon-o-matic/IconEditorApp.cpp +++ b/src/apps/icon-o-matic/IconEditorApp.cpp @@ -39,7 +39,7 @@ using std::nothrow; // constructor IconEditorApp::IconEditorApp() - : BApplication("application/x-vnd.Haiku-Icon-O-Matic"), + : BApplication("application/x-vnd.haiku-icon_o_matic"), fMainWindow(NULL), fDocument(new Document("test")), @@ -275,17 +275,24 @@ IconEditorApp::_Open(const entry_ref& ref, bool append) if (!icon) return; + enum { + REF_NONE = 0, + REF_MESSAGE, + REF_FLAT + }; + uint32 refMode = REF_NONE; + // try different file types FlatIconImporter flatImporter; status_t ret = flatImporter.Import(icon, &file); if (ret >= B_OK) { - fDocument->SetExportRef(ref); + refMode = REF_FLAT; } else { file.Seek(0, SEEK_SET); MessageImporter msgImporter; ret = msgImporter.Import(icon, &file); if (ret >= B_OK) { - fDocument->SetRef(ref); + refMode = REF_MESSAGE; } else { file.Seek(0, SEEK_SET); SVGImporter svgImporter; @@ -315,8 +322,18 @@ IconEditorApp::_Open(const entry_ref& ref, bool append) fMainWindow->SetIcon(NULL); fDocument->MakeEmpty(); + fDocument->SetIcon(icon); + switch (refMode) { + case REF_MESSAGE: + fDocument->SetRef(ref); + break; + case REF_FLAT: + fDocument->SetExportRef(ref); + break; + } + locker.Unlock(); if (mainWindowLocked) { diff --git a/src/apps/icon-o-matic/Jamfile b/src/apps/icon-o-matic/Jamfile index d0d2a5093c..293174bc45 100644 --- a/src/apps/icon-o-matic/Jamfile +++ b/src/apps/icon-o-matic/Jamfile @@ -231,6 +231,8 @@ Application Icon-O-Matic : AddShapesCommand.cpp AddTransformersCommand.cpp ChangePointCommand.cpp + CleanUpPathCommand.cpp + FreezeTransformationCommand.cpp InsertPointCommand.cpp MoveShapesCommand.cpp MovePathsCommand.cpp @@ -242,6 +244,8 @@ Application Icon-O-Matic : RemoveShapesCommand.cpp RemoveTransformersCommand.cpp ReversePathCommand.cpp + SplitPointsCommand.cpp + TransformPointsCommand.cpp UnassignPathCommand.cpp # style @@ -274,6 +278,8 @@ Application Icon-O-Matic : Util.cpp : be tracker translation libagg.a libexpat.a + + : Icon-O-Matic.rdef ; diff --git a/src/apps/icon-o-matic/MainWindow.cpp b/src/apps/icon-o-matic/MainWindow.cpp index 914f4d32cf..954380b76e 100644 --- a/src/apps/icon-o-matic/MainWindow.cpp +++ b/src/apps/icon-o-matic/MainWindow.cpp @@ -247,6 +247,8 @@ case MSG_SHAPE_SELECTED: { Shape* shape; if (message->FindPointer("shape", (void**)&shape) < B_OK) shape = NULL; + if (!fIcon || !fIcon->Shapes()->HasShape(shape)) + shape = NULL; fPathListView->SetCurrentShape(shape); fStyleListView->SetCurrentShape(shape); @@ -707,10 +709,21 @@ MainWindow::_CreateGUI(BRect bounds) // canvas view bounds.left = splitWidth; bounds.top = fSwatchGroup->Frame().bottom + 1; - bounds.right = bg->Bounds().right; - bounds.bottom = bg->Bounds().bottom; + bounds.right = bg->Bounds().right - B_V_SCROLL_BAR_WIDTH; + bounds.bottom = bg->Bounds().bottom - B_H_SCROLL_BAR_HEIGHT; fCanvasView = new CanvasView(bounds); + // scroll view around canvas view + bounds.bottom += B_H_SCROLL_BAR_HEIGHT; + bounds.right += B_V_SCROLL_BAR_WIDTH; + ScrollView* canvasScrollView + = new ScrollView(fCanvasView, + SCROLL_HORIZONTAL | SCROLL_VERTICAL + | SCROLL_VISIBLE_RECT_IS_CHILD_BOUNDS + | SCROLL_NO_FRAME, + bounds, "canvas scroll view", + B_FOLLOW_ALL, B_WILL_DRAW | B_FRAME_EVENTS); + // icon previews bounds.left = 5; bounds.top = fSwatchGroup->Frame().top + 5; @@ -882,7 +895,7 @@ MainWindow::_CreateGUI(BRect bounds) B_WILL_DRAW | B_FRAME_EVENTS)); - bg->AddChild(fCanvasView); + bg->AddChild(canvasScrollView); #endif // __HAIKU__ } diff --git a/src/apps/icon-o-matic/generic/gui/stateview/Manipulator.cpp b/src/apps/icon-o-matic/generic/gui/stateview/Manipulator.cpp index 2664128c39..90a5089716 100644 --- a/src/apps/icon-o-matic/generic/gui/stateview/Manipulator.cpp +++ b/src/apps/icon-o-matic/generic/gui/stateview/Manipulator.cpp @@ -68,6 +68,13 @@ Manipulator::DoubleClicked(BPoint where) return false; } +// ShowContextMenu +bool +Manipulator::ShowContextMenu(BPoint where) +{ + return false; +} + // #pragma mark - bool diff --git a/src/apps/icon-o-matic/generic/gui/stateview/Manipulator.h b/src/apps/icon-o-matic/generic/gui/stateview/Manipulator.h index 836f29e4c8..3c701102c0 100644 --- a/src/apps/icon-o-matic/generic/gui/stateview/Manipulator.h +++ b/src/apps/icon-o-matic/generic/gui/stateview/Manipulator.h @@ -33,6 +33,8 @@ class Manipulator : public Observer { virtual bool MouseOver(BPoint where); virtual bool DoubleClicked(BPoint where); + virtual bool ShowContextMenu(BPoint where); + virtual bool MessageReceived(BMessage* message, Command** _command); diff --git a/src/apps/icon-o-matic/generic/gui/stateview/MultipleManipulatorState.cpp b/src/apps/icon-o-matic/generic/gui/stateview/MultipleManipulatorState.cpp index 8a2c61fb29..c660031854 100644 --- a/src/apps/icon-o-matic/generic/gui/stateview/MultipleManipulatorState.cpp +++ b/src/apps/icon-o-matic/generic/gui/stateview/MultipleManipulatorState.cpp @@ -80,7 +80,10 @@ MultipleManipulatorState::MessageReceived(BMessage* message, void MultipleManipulatorState::MouseDown(BPoint where, uint32 buttons, uint32 clicks) { - // NOTE: buttons currently ignored + if (buttons & B_SECONDARY_MOUSE_BUTTON) { + _ShowContextMenu(where); + return; + } if (clicks == 2 && fPreviousManipulator @@ -281,3 +284,18 @@ MultipleManipulatorState::_UpdateCursor() else fView->SetViewCursor(B_CURSOR_SYSTEM_DEFAULT); } + +// _ShowContextMenu +void +MultipleManipulatorState::_ShowContextMenu(BPoint where) +{ + int32 count = fManipulators.CountItems(); + for (int32 i = 0; i < count; i++) { + Manipulator* manipulator = + (Manipulator*)fManipulators.ItemAtFast(i); + if (manipulator->ShowContextMenu(where)) + return; + } +} + + diff --git a/src/apps/icon-o-matic/generic/gui/stateview/MultipleManipulatorState.h b/src/apps/icon-o-matic/generic/gui/stateview/MultipleManipulatorState.h index a41cafca45..b1690fe748 100644 --- a/src/apps/icon-o-matic/generic/gui/stateview/MultipleManipulatorState.h +++ b/src/apps/icon-o-matic/generic/gui/stateview/MultipleManipulatorState.h @@ -55,6 +55,8 @@ class MultipleManipulatorState : public ViewState { private: void _UpdateCursor(); + void _ShowContextMenu(BPoint where); + BList fManipulators; Manipulator* fCurrentManipulator; diff --git a/src/apps/icon-o-matic/generic/gui/stateview/ViewState.cpp b/src/apps/icon-o-matic/generic/gui/stateview/ViewState.cpp index 2bfddfb443..8e293a2b1c 100644 --- a/src/apps/icon-o-matic/generic/gui/stateview/ViewState.cpp +++ b/src/apps/icon-o-matic/generic/gui/stateview/ViewState.cpp @@ -12,7 +12,7 @@ mouse_info::mouse_info() : buttons(0), - position(B_ORIGIN), + position(-1, -1), transit(B_OUTSIDE_VIEW), modifiers(::modifiers()) { diff --git a/src/apps/icon-o-matic/generic/gui/stateview/ViewState.h b/src/apps/icon-o-matic/generic/gui/stateview/ViewState.h index abb0b0dce9..814b9ce6fc 100644 --- a/src/apps/icon-o-matic/generic/gui/stateview/ViewState.h +++ b/src/apps/icon-o-matic/generic/gui/stateview/ViewState.h @@ -51,7 +51,6 @@ class ViewState { // modifiers virtual void ModifiersChanged(uint32 modifiers); - // TODO: mouse wheel virtual bool HandleKeyDown(uint32 key, uint32 modifiers, Command** _command); diff --git a/src/apps/icon-o-matic/gui/PathListView.cpp b/src/apps/icon-o-matic/gui/PathListView.cpp index 5c79b4a025..87793652c2 100644 --- a/src/apps/icon-o-matic/gui/PathListView.cpp +++ b/src/apps/icon-o-matic/gui/PathListView.cpp @@ -19,6 +19,7 @@ #include #include "AddPathsCommand.h" +#include "CleanUpPathCommand.h" #include "CommandStack.h" #include "MovePathsCommand.h" #include "Observer.h" @@ -236,6 +237,7 @@ enum { MSG_DUPLICATE = 'dupp', MSG_REVERSE = 'rvrs', + MSG_CLEAN_UP = 'clup', MSG_ROTATE_INDICES = 'roti', MSG_REMOVE = 'remp', @@ -430,6 +432,19 @@ PathListView::MessageReceived(BMessage* message) } break; + case MSG_CLEAN_UP: + if (fCommandStack) { + PathListItem* item = dynamic_cast( + ItemAt(CurrentSelection(0))); + if (!item) + break; + + CleanUpPathCommand* command + = new (nothrow) CleanUpPathCommand(item->path); + fCommandStack->Perform(command); + } + break; + case MSG_REMOVE: RemoveSelected(); break; @@ -701,6 +716,7 @@ PathListView::SetMenu(BMenu* menu) new BMessage(MSG_ADD_ARC)); fDuplicateMI = new BMenuItem("Duplicate", new BMessage(MSG_DUPLICATE)); fReverseMI = new BMenuItem("Reverse", new BMessage(MSG_REVERSE)); + fCleanUpMI = new BMenuItem("Clean Up", new BMessage(MSG_CLEAN_UP)); fRotateIndicesMI = new BMenuItem("Rotate Indices", new BMessage(MSG_ROTATE_INDICES)); fRemoveMI = new BMenuItem("Remove", new BMessage(MSG_REMOVE)); @@ -715,6 +731,7 @@ fAddArcMI->SetEnabled(false); fMenu->AddItem(fDuplicateMI); fMenu->AddItem(fReverseMI); + fMenu->AddItem(fCleanUpMI); fMenu->AddItem(fRotateIndicesMI); fMenu->AddSeparatorItem(); diff --git a/src/apps/icon-o-matic/gui/PathListView.h b/src/apps/icon-o-matic/gui/PathListView.h index 4eb290afb9..82cc465285 100644 --- a/src/apps/icon-o-matic/gui/PathListView.h +++ b/src/apps/icon-o-matic/gui/PathListView.h @@ -86,6 +86,7 @@ class PathListView : public SimpleListView, BMenuItem* fAddArcMI; BMenuItem* fDuplicateMI; BMenuItem* fReverseMI; + BMenuItem* fCleanUpMI; BMenuItem* fRotateIndicesMI; BMenuItem* fRemoveMI; diff --git a/src/apps/icon-o-matic/gui/ShapeListView.cpp b/src/apps/icon-o-matic/gui/ShapeListView.cpp index d6962b6723..6a00965176 100644 --- a/src/apps/icon-o-matic/gui/ShapeListView.cpp +++ b/src/apps/icon-o-matic/gui/ShapeListView.cpp @@ -23,6 +23,7 @@ #include "AddShapesCommand.h" #include "AddStylesCommand.h" #include "CommandStack.h" +#include "FreezeTransformationCommand.h" #include "MoveShapesCommand.h" #include "Observer.h" #include "RemoveShapesCommand.h" @@ -95,6 +96,7 @@ enum { MSG_REMOVE = 'rmsh', MSG_DUPLICATE = 'dpsh', MSG_RESET_TRANSFORMATION = 'rstr', + MSG_FREEZE_TRANSFORMATION = 'frzt', MSG_DRAG_SHAPE = 'drgs', }; @@ -165,17 +167,9 @@ ShapeListView::MessageReceived(BMessage* message) break; } case MSG_RESET_TRANSFORMATION: { - int32 count = CountSelectedItems(); BList shapes; - for (int32 i = 0; i < count; i++) { - ShapeListItem* item = dynamic_cast( - ItemAt(CurrentSelection(i))); - if (item && item->shape) { - if (!shapes.AddItem((void*)item->shape)) - break; - } - } - count = shapes.CountItems(); + _GetSelectedShapes(shapes); + int32 count = shapes.CountItems(); if (count < 0) break; @@ -191,6 +185,20 @@ ShapeListView::MessageReceived(BMessage* message) fCommandStack->Perform(command); break; } + case MSG_FREEZE_TRANSFORMATION: { + BList shapes; + _GetSelectedShapes(shapes); + int32 count = shapes.CountItems(); + if (count < 0) + break; + + FreezeTransformationCommand* command = + new FreezeTransformationCommand((Shape**)shapes.Items(), + count); + + fCommandStack->Perform(command); + break; + } default: SimpleListView::MessageReceived(message); break; @@ -433,6 +441,8 @@ ShapeListView::SetMenu(BMenu* menu) fDuplicateMI = new BMenuItem("Duplicate", new BMessage(MSG_DUPLICATE)); fResetTransformationMI = new BMenuItem("Reset Transformation", new BMessage(MSG_RESET_TRANSFORMATION)); + fFreezeTransformationMI = new BMenuItem("Freeze Transformation", + new BMessage(MSG_FREEZE_TRANSFORMATION)); fRemoveMI = new BMenuItem("Remove", new BMessage(MSG_REMOVE)); @@ -446,6 +456,7 @@ ShapeListView::SetMenu(BMenu* menu) fMenu->AddItem(fDuplicateMI); fMenu->AddItem(fResetTransformationMI); + fMenu->AddItem(fFreezeTransformationMI); fMenu->AddSeparatorItem(); @@ -453,6 +464,7 @@ ShapeListView::SetMenu(BMenu* menu) fDuplicateMI->SetTarget(this); fResetTransformationMI->SetTarget(this); + fFreezeTransformationMI->SetTarget(this); fRemoveMI->SetTarget(this); _UpdateMenu(); @@ -541,4 +553,17 @@ ShapeListView::_UpdateMenu() fRemoveMI->SetEnabled(gotSelection); } - +// _GetSelectedShapes +void +ShapeListView::_GetSelectedShapes(BList& shapes) const +{ + int32 count = CountSelectedItems(); + for (int32 i = 0; i < count; i++) { + ShapeListItem* item = dynamic_cast( + ItemAt(CurrentSelection(i))); + if (item && item->shape) { + if (!shapes.AddItem((void*)item->shape)) + break; + } + } +} diff --git a/src/apps/icon-o-matic/gui/ShapeListView.h b/src/apps/icon-o-matic/gui/ShapeListView.h index 20f30ddef4..ce0ccb77e1 100644 --- a/src/apps/icon-o-matic/gui/ShapeListView.h +++ b/src/apps/icon-o-matic/gui/ShapeListView.h @@ -68,6 +68,8 @@ class ShapeListView : public SimpleListView, ShapeListItem* _ItemForShape(Shape* shape) const; void _UpdateMenu(); + void _GetSelectedShapes(BList& shapes) const; + BMessage* fMessage; ShapeContainer* fShapeContainer; @@ -80,6 +82,7 @@ class ShapeListView : public SimpleListView, BMenuItem* fAddWidthPathAndStyleMI; BMenuItem* fDuplicateMI; BMenuItem* fResetTransformationMI; + BMenuItem* fFreezeTransformationMI; BMenuItem* fRemoveMI; }; diff --git a/src/apps/icon-o-matic/import_export/svg/DocumentBuilder.cpp b/src/apps/icon-o-matic/import_export/svg/DocumentBuilder.cpp index 18821841ca..e5400c04ce 100644 --- a/src/apps/icon-o-matic/import_export/svg/DocumentBuilder.cpp +++ b/src/apps/icon-o-matic/import_export/svg/DocumentBuilder.cpp @@ -477,19 +477,27 @@ DocumentBuilder::GetIcon(Icon* icon, SVGImporter* importer, yMax = ceil(yMax); BRect bounds; - if (fViewBox.IsValid()) + if (fViewBox.IsValid()) { bounds = fViewBox; - else +printf("view box: "); +bounds.PrintToStream(); + } else { bounds.Set(0.0, 0.0, (int32)fWidth - 1, (int32)fHeight - 1); +printf("width/height: "); +bounds.PrintToStream(); + } BRect boundingBox(xMin, yMin, xMax, yMax); if (!bounds.IsValid() || !boundingBox.Intersects(bounds)) { bounds = boundingBox; +printf("using bounding box: "); +bounds.PrintToStream(); } - float size = max_c(bounds.Width() + 1.0, bounds.Height() + 1.0); + float size = min_c(bounds.Width() + 1.0, bounds.Height() + 1.0); double scale = 64.0 / size; +printf("scale: %f\n", scale); Transformable transform; transform.TranslateBy(BPoint(-bounds.left, -bounds.top)); @@ -540,6 +548,8 @@ DocumentBuilder::EndGradient() fCurrentGradient = NULL; } +// #pragma mark - + // _AddGradient void DocumentBuilder::_AddGradient(SVGGradient* gradient) diff --git a/src/apps/icon-o-matic/shape/PathManipulator.cpp b/src/apps/icon-o-matic/shape/PathManipulator.cpp index 7e0795a9c4..853b544ed4 100644 --- a/src/apps/icon-o-matic/shape/PathManipulator.cpp +++ b/src/apps/icon-o-matic/shape/PathManipulator.cpp @@ -13,6 +13,8 @@ #include #include +#include +#include #include #include "cursors.h" @@ -31,6 +33,7 @@ //#include "ReversePathCommand.h" //#include "SelectPathCommand.h" //#include "SelectPointsCommand.h" +#include "SplitPointsCommand.h" #include "TransformPointsBox.h" #define POINT_EXTEND 3.0 @@ -65,6 +68,14 @@ enum { SELECT_SUB_PATH, }; +enum { + MSG_TRANSFORM = 'strn', + MSG_REMOVE_POINTS = 'srmp', + MSG_UPDATE_SHAPE_UI = 'udsi', + + MSG_SPLIT_POINTS = 'splt', +}; + inline const char* string_for_mode(uint32 mode) { @@ -480,18 +491,29 @@ PathManipulator::MouseDown(BPoint where) _RemovePointOut(fCurrentPathPoint); break; - case SELECT_POINTS: - if (!fShiftDown) { + case SELECT_POINTS: { + // TODO: this works so that you can deselect all points + // when clicking outside the path even if pressing shift + // in case the path is open... a better way would be + // to deselect all on mouse up, if the mouse has not moved + bool appendSelection; + if (fPath->IsClosed()) + appendSelection = fShiftDown; + else + appendSelection = fShiftDown && fCurrentPathPoint >= 0; + + if (!appendSelection) { fSelection->MakeEmpty(); _UpdateSelection(); } *fOldSelection = *fSelection; if (fCurrentPathPoint >= 0) { - _Select(fCurrentPathPoint, fShiftDown); + _Select(fCurrentPathPoint, appendSelection); } fCanvasView->BeginRectTracking(BRect(where, where), B_TRACK_RECT_CORNER); break; + } } fTrackingStart = canvasWhere; @@ -707,6 +729,52 @@ PathManipulator::DoubleClicked(BPoint where) return false; } +// ShowContextMenu +bool +PathManipulator::ShowContextMenu(BPoint where) +{ + BPopUpMenu* menu = new BPopUpMenu("context menu", false, false); + BMessage* message; + BMenuItem* item; + + bool hasSelection = fSelection->CountItems() > 0; + + message = new BMessage(B_SELECT_ALL); + item = new BMenuItem("Select All", message, 'A'); + menu->AddItem(item); + + menu->AddSeparatorItem(); + + message = new BMessage(MSG_TRANSFORM); + item = new BMenuItem("Transform", message); + item->SetEnabled(hasSelection); + menu->AddItem(item); + + message = new BMessage(MSG_SPLIT_POINTS); + item = new BMenuItem("Split", message); + item->SetEnabled(hasSelection); + menu->AddItem(item); + + message = new BMessage(MSG_REMOVE_POINTS); + item = new BMenuItem("Remove", message, 'A'); + item->SetEnabled(hasSelection); + menu->AddItem(item); + + // go + menu->SetTargetForItems(fCanvasView); + menu->SetAsyncAutoDestruct(true); + menu->SetFont(be_plain_font); + where = fCanvasView->ConvertToScreen(where); + BRect mouseRect(where, where); + mouseRect.InsetBy(-10.0, -10.0); + where += BPoint(5.0, 5.0); + menu->Go(where, true, false, mouseRect, true); + + return true; +} + +// #pragma mark - + // Bounds BRect PathManipulator::Bounds() @@ -725,25 +793,24 @@ PathManipulator::TrackingBounds(BView* withinView) // #pragma mark - -enum { - MSG_SHAPE_TRANSFORM = 'strn', - MSG_SHAPE_REMOVE_POINTS = 'srmp', - MSG_UPDATE_SHAPE_UI = 'udsi', -}; - // MessageReceived bool PathManipulator::MessageReceived(BMessage* message, Command** _command) { bool result = true; switch (message->what) { - case MSG_SHAPE_TRANSFORM: + case MSG_TRANSFORM: if (!fSelection->IsEmpty()) _SetMode(TRANSFORM_POINTS); break; - case MSG_SHAPE_REMOVE_POINTS: + case MSG_REMOVE_POINTS: *_command = _Delete(); break; + case MSG_SPLIT_POINTS: + *_command = new SplitPointsCommand(fPath, + fSelection->Items(), + fSelection->CountItems()); + break; case B_SELECT_ALL: { *fOldSelection = *fSelection; fSelection->MakeEmpty(); @@ -1292,10 +1359,12 @@ void PathManipulator::_Select(BRect r) { BPoint p; + BPoint pIn; + BPoint pOut; int32 count = fPath->CountPoints(); Selection temp; - for (int32 i = 0; i < count && fPath->GetPointAt(i, p); i++) { - if (r.Contains(p)) { + for (int32 i = 0; i < count && fPath->GetPointsAt(i, p, pIn, pOut); i++) { + if (r.Contains(p) || r.Contains(pIn) || r.Contains(pOut)) { temp.Add(i); } } diff --git a/src/apps/icon-o-matic/shape/PathManipulator.h b/src/apps/icon-o-matic/shape/PathManipulator.h index 762c13c63d..ae3a7a9076 100644 --- a/src/apps/icon-o-matic/shape/PathManipulator.h +++ b/src/apps/icon-o-matic/shape/PathManipulator.h @@ -45,6 +45,8 @@ class PathManipulator : public Manipulator, virtual bool MouseOver(BPoint where); virtual bool DoubleClicked(BPoint where); + virtual bool ShowContextMenu(BPoint where); + virtual BRect Bounds(); virtual BRect TrackingBounds(BView* withinView); diff --git a/src/apps/icon-o-matic/shape/commands/CleanUpPathCommand.cpp b/src/apps/icon-o-matic/shape/commands/CleanUpPathCommand.cpp new file mode 100644 index 0000000000..49e0f77630 --- /dev/null +++ b/src/apps/icon-o-matic/shape/commands/CleanUpPathCommand.cpp @@ -0,0 +1,52 @@ +/* + * Copyright 2006, Haiku. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Stephan Aßmus + */ + +#include "CleanUpPathCommand.h" + +#include + +#include "VectorPath.h" + +// constructor +CleanUpPathCommand::CleanUpPathCommand(VectorPath* path) + : PathCommand(path), + fOriginalPath() +{ + if (fPath) + fOriginalPath = *fPath; +} + +// destructor +CleanUpPathCommand::~CleanUpPathCommand() +{ +} + +// Perform +status_t +CleanUpPathCommand::Perform() +{ + fPath->CleanUp(); + + return B_OK; +} + +// Undo +status_t +CleanUpPathCommand::Undo() +{ + *fPath = fOriginalPath; + + return B_OK; +} + +// GetName +void +CleanUpPathCommand::GetName(BString& name) +{ + name << "Clean Up Path"; +} diff --git a/src/apps/icon-o-matic/shape/commands/CleanUpPathCommand.h b/src/apps/icon-o-matic/shape/commands/CleanUpPathCommand.h new file mode 100644 index 0000000000..cbc565d65b --- /dev/null +++ b/src/apps/icon-o-matic/shape/commands/CleanUpPathCommand.h @@ -0,0 +1,29 @@ +/* + * Copyright 2006, Haiku. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Stephan Aßmus + */ + +#ifndef CLEAN_UP_PATH_COMMAND_H +#define CLEAN_UP_PATH_COMMAND_H + +#include "PathCommand.h" +#include "VectorPath.h" + +class CleanUpPathCommand : public PathCommand { + public: + CleanUpPathCommand(VectorPath* path); + virtual ~CleanUpPathCommand(); + + virtual status_t Perform(); + virtual status_t Undo(); + + virtual void GetName(BString& name); + + private: + VectorPath fOriginalPath; +}; + +#endif // CLEAN_UP_PATH_COMMAND_H diff --git a/src/apps/icon-o-matic/shape/commands/FreezeTransformationCommand.cpp b/src/apps/icon-o-matic/shape/commands/FreezeTransformationCommand.cpp new file mode 100644 index 0000000000..6afa8f1430 --- /dev/null +++ b/src/apps/icon-o-matic/shape/commands/FreezeTransformationCommand.cpp @@ -0,0 +1,152 @@ +/* + * Copyright 2006, Haiku. + * Distributed under the terms of the MIT License. + * + * Authors: + * Stephan Aßmus + */ + +#include "FreezeTransformationCommand.h" + +#include +#include +#include + +#include "Gradient.h" +#include "Shape.h" +#include "Style.h" +#include "VectorPath.h" + +using std::nothrow; + +// constructor +FreezeTransformationCommand::FreezeTransformationCommand( + Shape** const shapes, + int32 count) + : Command(), + fShapes(shapes && count > 0 ? new (nothrow) Shape*[count] : NULL), + fOriginalTransformations(count > 0 ? new (nothrow) double[ + count * Transformable::matrix_size] + : NULL), + fCount(count) +{ + if (!fShapes || !fOriginalTransformations) + return; + + memcpy(fShapes, shapes, sizeof(Shape*) * fCount); + + bool initOk = false; + + for (int32 i = 0; i < fCount; i++) { + if (!fShapes[i]) + continue; + if (!fShapes[i]->IsIdentity()) + initOk = true; + fShapes[i]->StoreTo(&fOriginalTransformations[ + i * Transformable::matrix_size]); + } + + if (!initOk) { + delete[] fShapes; + fShapes = NULL; + delete[] fOriginalTransformations; + fOriginalTransformations = NULL; + } +} + +// destructor +FreezeTransformationCommand::~FreezeTransformationCommand() +{ + delete[] fShapes; + delete[] fOriginalTransformations; +} + +// InitCheck +status_t +FreezeTransformationCommand::InitCheck() +{ + return fShapes && fOriginalTransformations ? B_OK : B_NO_INIT; +} + +// Perform +status_t +FreezeTransformationCommand::Perform() +{ + for (int32 i = 0; i < fCount; i++) { + if (!fShapes[i] || fShapes[i]->IsIdentity()) + continue; + + _ApplyTransformation(fShapes[i], *(fShapes[i])); + fShapes[i]->Reset(); + } + + return B_OK; +} + +// Undo +status_t +FreezeTransformationCommand::Undo() +{ + for (int32 i = 0; i < fCount; i++) { + if (!fShapes[i]) + continue; + + // restore original transformation + fShapes[i]->LoadFrom(&fOriginalTransformations[ + i * Transformable::matrix_size]); + + Transformable transform(*(fShapes[i])); + if (!transform.IsValid() || transform.IsIdentity()) + continue; + + transform.Invert(); + _ApplyTransformation(fShapes[i], transform); + } + + return B_OK; +} + +// GetName +void +FreezeTransformationCommand::GetName(BString& name) +{ + if (fCount > 1) + name << "Freeze Shapes"; + else + name << "Freeze Shape"; +} + +// #pragma mark - + +// _ApplyTransformation +void +FreezeTransformationCommand::_ApplyTransformation(Shape* shape, + const Transformable& transform) +{ + // apply inverse of old shape transformation to every assigned path + int32 pathCount = shape->Paths()->CountPaths(); + for (int32 i = 0; i < pathCount; i++) { + VectorPath* path = shape->Paths()->PathAtFast(i); + int32 shapes = 0; + int32 listeners = path->CountListeners(); + for (int32 j = 0; j < listeners; j++) { + if (dynamic_cast(path->ListenerAtFast(j))) + shapes++; + } + // only freeze transformation of path if only one + // shape has it assigned + if (shapes == 1) { + path->ApplyTransform(transform); + } else { + printf("Not transfering transformation of \"%s\" onto " + "path \"%s\", because %ld other shapes " + "have it assigned.\n", shape->Name(), path->Name(), + shapes - 1); + } + } + // take care of style too + if (shape->Style() && shape->Style()->Gradient()) { + // TODO: not if more than one shape have this style assigned! + shape->Style()->Gradient()->Multiply(transform); + } +} diff --git a/src/apps/icon-o-matic/shape/commands/FreezeTransformationCommand.h b/src/apps/icon-o-matic/shape/commands/FreezeTransformationCommand.h new file mode 100644 index 0000000000..667d021d3c --- /dev/null +++ b/src/apps/icon-o-matic/shape/commands/FreezeTransformationCommand.h @@ -0,0 +1,40 @@ +/* + * Copyright 2006, Haiku. + * Distributed under the terms of the MIT License. + * + * Authors: + * Stephan Aßmus + */ + +#ifndef FREEZE_TRANSFORMATION_COMMAND_H +#define FREEZE_TRANSFORMATION_COMMAND_H + +#include "Command.h" + +class Shape; +class Transformable; + +class FreezeTransformationCommand : public Command { + public: + FreezeTransformationCommand( + Shape** const shapes, + int32 count); + virtual ~FreezeTransformationCommand(); + + virtual status_t InitCheck(); + + virtual status_t Perform(); + virtual status_t Undo(); + + virtual void GetName(BString& name); + + private: + void _ApplyTransformation(Shape* shape, + const Transformable& transform); + + Shape** fShapes; + double* fOriginalTransformations; + int32 fCount; +}; + +#endif // FREEZE_TRANSFORMATION_COMMAND_H diff --git a/src/apps/icon-o-matic/shape/commands/ReversePathCommand.cpp b/src/apps/icon-o-matic/shape/commands/ReversePathCommand.cpp index e87b8add4c..24a4084ec8 100644 --- a/src/apps/icon-o-matic/shape/commands/ReversePathCommand.cpp +++ b/src/apps/icon-o-matic/shape/commands/ReversePathCommand.cpp @@ -1,3 +1,11 @@ +/* + * Copyright 2006, Haiku. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Stephan Aßmus + */ + #include "ReversePathCommand.h" #include diff --git a/src/apps/icon-o-matic/shape/commands/ReversePathCommand.h b/src/apps/icon-o-matic/shape/commands/ReversePathCommand.h index 8f62846b12..a691588523 100644 --- a/src/apps/icon-o-matic/shape/commands/ReversePathCommand.h +++ b/src/apps/icon-o-matic/shape/commands/ReversePathCommand.h @@ -1,3 +1,11 @@ +/* + * Copyright 2006, Haiku. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Stephan Aßmus + */ + #ifndef REVERSE_PATH_COMMAND_H #define REVERSE_PATH_COMMAND_H diff --git a/src/apps/icon-o-matic/shape/commands/SplitPointsCommand.cpp b/src/apps/icon-o-matic/shape/commands/SplitPointsCommand.cpp new file mode 100644 index 0000000000..888c8833d1 --- /dev/null +++ b/src/apps/icon-o-matic/shape/commands/SplitPointsCommand.cpp @@ -0,0 +1,154 @@ +/* + * Copyright 2006, Haiku. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Stephan Aßmus + */ + +#include "SplitPointsCommand.h" + +#include +#include + +#include "VectorPath.h" + +using std::nothrow; + +// constructor +// * when hitting the Delete key, so the selected points are the +// same as the ones to be removed +SplitPointsCommand::SplitPointsCommand(VectorPath* path, + const int32* indices, + int32 count) + : PathCommand(path), + fIndex(NULL), + fPoint(NULL), + fPointIn(NULL), + fPointOut(NULL), + fConnected(NULL), + fCount(0) +{ + if (indices && count > 0) { + fIndex = new (nothrow) int32[count]; + fPoint = new (nothrow) BPoint[count]; + fPointIn = new (nothrow) BPoint[count]; + fPointOut = new (nothrow) BPoint[count]; + fConnected = new (nothrow) bool[count]; + fCount = count; + } + + if (InitCheck() < B_OK) + return; + + memcpy(fIndex, indices, count * sizeof(int32)); + for (int32 i = 0; i < count; i++) { + if (!fPath->GetPointsAt(fIndex[i], + fPoint[i], + fPointIn[i], + fPointOut[i], + &fConnected[i])) { + fPath = NULL; + break; + } + } +} + +// destructor +SplitPointsCommand::~SplitPointsCommand() +{ + delete[] fIndex; + delete[] fPoint; + delete[] fPointIn; + delete[] fPointOut; + delete[] fConnected; +} + +// InitCheck +status_t +SplitPointsCommand::InitCheck() +{ + status_t status = PathCommand::InitCheck(); + if (status < B_OK) + return status; + if (!fIndex || !fPoint || !fPointIn || !fPointOut || !fConnected) + status = B_NO_MEMORY; + return status; +} + +// Perform +status_t +SplitPointsCommand::Perform() +{ + status_t status = B_OK; + + AutoNotificationSuspender _(fPath); + + // NOTE: fCount guaranteed > 0 + // add points again at their respective index + for (int32 i = 0; i < fCount; i++) { + int32 index = fIndex[i] + 1 + i; + // "+ 1" to insert behind existing point + // "+ i" to adjust for already inserted points + if (fPath->AddPoint(fPoint[i], index)) { + fPath->SetPoint(index - 1, + fPoint[i], + fPointIn[i], + fPoint[i], + true); + fPath->SetPoint(index, + fPoint[i], + fPoint[i], + fPointOut[i], + true); + } else { + status = B_ERROR; + break; + } + } + + return status; +} + +// Undo +status_t +SplitPointsCommand::Undo() +{ + status_t status = B_OK; + + AutoNotificationSuspender _(fPath); + + // remove inserted points and reset modified + // points to previous condition + for (int32 i = 0; i < fCount; i++) { + int32 index = fIndex[i] + 1; + if (fPath->RemovePoint(index)) { + fPath->SetPoint(index - 1, + fPoint[i], + fPointIn[i], + fPointOut[i], + fConnected[i]); + } else { + status = B_ERROR; + break; + } + } + + if (status >= B_OK) { + // restore selection + _Select(fIndex, fCount); + } + + return status; +} + +// GetName +void +SplitPointsCommand::GetName(BString& name) +{ + if (fCount > 1) + name << "Split Control Points"; + else + name << "Split Control Point"; +} + diff --git a/src/apps/icon-o-matic/shape/commands/SplitPointsCommand.h b/src/apps/icon-o-matic/shape/commands/SplitPointsCommand.h new file mode 100644 index 0000000000..f899d65d97 --- /dev/null +++ b/src/apps/icon-o-matic/shape/commands/SplitPointsCommand.h @@ -0,0 +1,39 @@ +/* + * Copyright 2006, Haiku. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Stephan Aßmus + */ + +#ifndef SPLIT_POINTS_COMMAND_H +#define SPLIT_POINTS_COMMAND_H + +#include "PathCommand.h" + +class BPoint; + +class SplitPointsCommand : public PathCommand { + public: + SplitPointsCommand(VectorPath* path, + const int32* indices, + int32 count); + virtual ~SplitPointsCommand(); + + virtual status_t InitCheck(); + + virtual status_t Perform(); + virtual status_t Undo(); + + virtual void GetName(BString& name); + + private: + int32* fIndex; + BPoint* fPoint; + BPoint* fPointIn; + BPoint* fPointOut; + bool* fConnected; + int32 fCount; +}; + +#endif // SPLIT_POINTS_COMMAND_H diff --git a/src/apps/icon-o-matic/shape/commands/TransformPointsCommand.cpp b/src/apps/icon-o-matic/shape/commands/TransformPointsCommand.cpp new file mode 100644 index 0000000000..222a455140 --- /dev/null +++ b/src/apps/icon-o-matic/shape/commands/TransformPointsCommand.cpp @@ -0,0 +1,122 @@ +/* + * Copyright 2006, Haiku. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Stephan Aßmus + */ + +#include "TransformPointsCommand.h" + +#include +#include + +#include "ChannelTransform.h" +#include "VectorPath.h" + +// constructor +TransformPointsCommand::TransformPointsCommand( + TransformBox* box, + + VectorPath* path, + const int32* indices, + const control_point* points, + int32 count, + + BPoint pivot, + BPoint translation, + double rotation, + double xScale, + double yScale, + + const char* name, + int32 nameIndex) + : TransformCommand(pivot, + translation, + rotation, + xScale, + yScale, + name, + nameIndex), + fTransformBox(box), + fPath(path), + fIndices(indices && count > 0 ? + new (nothrow) int32[count] : NULL), + fPoints(points && count > 0 ? + new (nothrow) control_point[count] : NULL), + fCount(count) +{ + if (!fIndices || !fPoints) + return; + + memcpy(fIndices, indices, fCount * sizeof(int32)); + memcpy(fPoints, points, fCount * sizeof(control_point)); + + if (fTransformBox) + fTransformBox->AddListener(this); +} + +// destructor +TransformPointsCommand::~TransformPointsCommand() +{ + if (fTransformBox) + fTransformBox->RemoveListener(this); + + delete[] fIndices; + delete[] fPoints; +} + +// InitCheck +status_t +TransformPointsCommand::InitCheck() +{ + return fPath && fIndices && fPoints ? TransformCommand::InitCheck() + : B_NO_INIT; +} + +// #pragma mark - + +// TransformBoxDeleted +void +TransformPointsCommand::TransformBoxDeleted( + const TransformBox* box) +{ + if (fTransformBox == box) { + if (fTransformBox) + fTransformBox->RemoveListener(this); + fTransformBox = NULL; + } +} + +// #pragma mark - + +// _SetTransformation +status_t +TransformPointsCommand::_SetTransformation( + BPoint pivot, BPoint translation, + double rotation, + double xScale, double yScale) const +{ + if (fTransformBox) { + fTransformBox->SetTransformation(pivot, translation, + rotation, xScale, yScale); + return B_OK; + } + + + ChannelTransform transform; + transform.SetTransformation(pivot, translation, + rotation, xScale, yScale); + // restore original points and apply transformation + for (int32 i = 0; i < fCount; i++) { + BPoint point = transform.Transform(fPoints[i].point); + BPoint pointIn = transform.Transform(fPoints[i].point_in); + BPoint pointOut = transform.Transform(fPoints[i].point_out); + if (!fPath->SetPoint(fIndices[i], point, pointIn, pointOut, + fPoints[i].connected)) + return B_ERROR; + } + + return B_OK; +} + diff --git a/src/apps/icon-o-matic/shape/commands/TransformPointsCommand.h b/src/apps/icon-o-matic/shape/commands/TransformPointsCommand.h new file mode 100644 index 0000000000..05cd537b2e --- /dev/null +++ b/src/apps/icon-o-matic/shape/commands/TransformPointsCommand.h @@ -0,0 +1,63 @@ +/* + * Copyright 2006, Haiku. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Stephan Aßmus + */ + +#ifndef TRANSFORM_POINTS_COMMAND_H +#define TRANSFORM_POINTS_COMMAND_H + +#include "TransformBox.h" +#include "TransformCommand.h" + +class Transformable; +class VectorPath; +struct control_point; + +class TransformPointsCommand : public TransformCommand, + public TransformBoxListener { + public: + TransformPointsCommand( + TransformBox* box, + + VectorPath* path, + const int32* indices, + const control_point* points, + int32 count, + + BPoint pivot, + BPoint translation, + double rotation, + double xScale, + double yScale, + + const char* name, + int32 nameIndex); + virtual ~TransformPointsCommand(); + + // Command interface + virtual status_t InitCheck(); + + // TransformBoxListener interface + virtual void TransformBoxDeleted( + const TransformBox* box); + protected: + // TransformCommand interface + virtual status_t _SetTransformation(BPoint pivotDiff, + BPoint translationDiff, + double rotationDiff, + double xScaleDiff, + double yScaleDiff) const; + + TransformBox* fTransformBox; + + VectorPath* fPath; + + int32* fIndices; + control_point* fPoints; + int32 fCount; +}; + +#endif // TRANSFORM_POINTS_COMMAND_H diff --git a/src/apps/icon-o-matic/transformable/TransformPointsBox.cpp b/src/apps/icon-o-matic/transformable/TransformPointsBox.cpp index 8b075dd99a..005a5cb9e6 100644 --- a/src/apps/icon-o-matic/transformable/TransformPointsBox.cpp +++ b/src/apps/icon-o-matic/transformable/TransformPointsBox.cpp @@ -12,9 +12,8 @@ #include #include -//#include "ExitTransformPointsCommand.h" #include "StateView.h" -//#include "TransformPointsCommand.h" +#include "TransformPointsCommand.h" #include "VectorPath.h" using std::nothrow; @@ -118,19 +117,20 @@ TransformCommand* TransformPointsBox::MakeCommand(const char* commandName, uint32 nameIndex) { - return NULL; -// return new TransformPointsAction(fManipulator, -// fIndices, -// fPoints, -// fCount, -//// Translation(), -//// LocalRotation(), -//// LocalXScale(), -//// LocalYScale(), -// *this, -// CenterOffset(), -// actionName, -// nameIndex); + return new TransformPointsCommand(this, fPath, + + fIndices, + fPoints, + fCount, + + Pivot(), + Translation(), + LocalRotation(), + LocalXScale(), + LocalYScale(), + + commandName, + nameIndex); } // #pragma mark -