1 /* 2 * Copyright 2006, Haiku. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Stephan Aßmus <superstippi@gmx.de> 7 */ 8 9 #include "TransformShapesBox.h" 10 11 #include <new> 12 #include <stdio.h> 13 #include <string.h> 14 15 #include "Shape.h" 16 #include "StateView.h" 17 #include "TransformObjectsCommand.h" 18 19 using std::nothrow; 20 21 // constructor 22 TransformShapesBox::TransformShapesBox(CanvasView* view, 23 const Shape** shapes, 24 int32 count) 25 : CanvasTransformBox(view), 26 27 fShapes(shapes && count > 0 ? new Shape*[count] : NULL), 28 fCount(count), 29 30 fOriginals(NULL), 31 32 fParentTransform() 33 { 34 if (fShapes != NULL) { 35 // allocate storage for the current transformations 36 // of each object 37 fOriginals = new double[fCount * Transformable::matrix_size]; 38 39 memcpy(fShapes, shapes, fCount * sizeof(Shape*)); 40 41 for (int32 i = 0; i < fCount; i++) { 42 if (fShapes[i]) { 43 fShapes[i]->Acquire(); 44 fShapes[i]->AddObserver(this); 45 } 46 } 47 48 // trigger init 49 ObjectChanged(fShapes[0]); 50 } else { 51 SetBox(BRect(0, 0, -1, -1)); 52 } 53 } 54 55 // destructor 56 TransformShapesBox::~TransformShapesBox() 57 { 58 if (fShapes) { 59 for (int32 i = 0; i < fCount; i++) { 60 if (fShapes[i]) { 61 fShapes[i]->RemoveObserver(this); 62 fShapes[i]->Release(); 63 } 64 } 65 delete[] fShapes; 66 } 67 68 delete[] fOriginals; 69 } 70 71 // Update 72 void 73 TransformShapesBox::Update(bool deep) 74 { 75 BRect r = Bounds(); 76 77 TransformBox::Update(deep); 78 79 BRect dirty(r | Bounds()); 80 dirty.InsetBy(-8, -8); 81 fView->Invalidate(dirty); 82 83 if (!deep || !fShapes) 84 return; 85 86 for (int32 i = 0; i < fCount; i++) { 87 if (!fShapes[i]) 88 continue; 89 90 fShapes[i]->RemoveObserver(this); 91 fShapes[i]->SuspendNotifications(true); 92 93 // reset the objects transformation to the saved state 94 fShapes[i]->LoadFrom(&fOriginals[i * Transformable::matrix_size]); 95 // combined with the current transformation 96 fShapes[i]->Multiply(*this); 97 98 fShapes[i]->SuspendNotifications(false); 99 fShapes[i]->AddObserver(this); 100 } 101 } 102 103 // ObjectChanged 104 void 105 TransformShapesBox::ObjectChanged(const Observable* object) 106 { 107 if (!fView->LockLooper()) 108 return; 109 110 fParentTransform.Reset(); 111 // figure out bounds and store initial transformations 112 BRect box(LONG_MAX, LONG_MAX, LONG_MIN, LONG_MIN); 113 for (int32 i = 0; i < fCount; i++) { 114 if (!fShapes[i]) 115 continue; 116 117 box = box | fShapes[i]->Bounds(); 118 fShapes[i]->StoreTo(&fOriginals[i * Transformable::matrix_size]); 119 } 120 // any TransformObjectsCommand cannot use the TransformBox 121 // anymore 122 _NotifyDeleted(); 123 124 Reset(); 125 SetBox(box); 126 127 fView->UnlockLooper(); 128 } 129 130 // MakeCommand 131 TransformCommand* 132 TransformShapesBox::MakeCommand(const char* commandName, uint32 nameIndex) 133 { 134 Transformable* objects[fCount]; 135 for (int32 i = 0; i < fCount; i++) 136 objects[i] = fShapes[i]; 137 138 return new TransformObjectsCommand(this, objects, fOriginals, fCount, 139 140 Pivot(), 141 Translation(), 142 LocalRotation(), 143 LocalXScale(), 144 LocalYScale(), 145 146 commandName, 147 nameIndex); 148 } 149 150