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 "CanvasView.h" 16 #include "Shape.h" 17 #include "StateView.h" 18 #include "TransformObjectsCommand.h" 19 20 using std::nothrow; 21 22 // constructor 23 TransformShapesBox::TransformShapesBox(CanvasView* view, 24 const Shape** shapes, 25 int32 count) 26 : TransformBox(view, BRect(0.0, 0.0, 1.0, 1.0)), 27 28 fCanvasView(view), 29 30 fShapes(shapes && count > 0 ? new Shape*[count] : NULL), 31 fCount(count), 32 33 fOriginals(NULL), 34 35 fParentTransform() 36 { 37 if (fShapes) { 38 // allocate storage for the current transformations 39 // of each object 40 fOriginals = new double[fCount * 6]; 41 42 memcpy(fShapes, shapes, fCount * sizeof(Shape*)); 43 44 for (int32 i = 0; i < fCount; i++) { 45 if (fShapes[i]) 46 fShapes[i]->AddObserver(this); 47 } 48 49 // trigger init 50 ObjectChanged(fShapes[0]); 51 } else { 52 SetBox(BRect(0, 0, -1, -1)); 53 } 54 } 55 56 // destructor 57 TransformShapesBox::~TransformShapesBox() 58 { 59 if (fShapes) { 60 for (int32 i = 0; i < fCount; i++) { 61 if (fShapes[i]) 62 fShapes[i]->RemoveObserver(this); 63 } 64 delete[] fShapes; 65 } 66 67 delete[] fOriginals; 68 } 69 70 // Update 71 void 72 TransformShapesBox::Update(bool deep) 73 { 74 BRect r = Bounds(); 75 76 TransformBox::Update(deep); 77 78 BRect dirty(r | Bounds()); 79 dirty.InsetBy(-8, -8); 80 fView->Invalidate(dirty); 81 82 if (!deep || !fShapes) 83 return; 84 85 for (int32 i = 0; i < fCount; i++) { 86 if (!fShapes[i]) 87 continue; 88 89 fShapes[i]->RemoveObserver(this); 90 fShapes[i]->SuspendNotifications(true); 91 92 // reset the objects transformation to the saved state 93 fShapes[i]->LoadFrom(&fOriginals[i * 6]); 94 // combined with the current transformation 95 fShapes[i]->Multiply(*this); 96 97 fShapes[i]->SuspendNotifications(false); 98 fShapes[i]->AddObserver(this); 99 } 100 } 101 102 // ObjectChanged 103 void 104 TransformShapesBox::ObjectChanged(const Observable* object) 105 { 106 if (!fView->LockLooper()) 107 return; 108 109 fParentTransform.Reset(); 110 // figure out bounds and store initial transformations 111 BRect box(LONG_MAX, LONG_MAX, LONG_MIN, LONG_MIN); 112 for (int32 i = 0; i < fCount; i++) { 113 if (!fShapes[i]) 114 continue; 115 116 box = box | fShapes[i]->Bounds(); 117 fShapes[i]->StoreTo(&fOriginals[i * 6]); 118 } 119 // any TransformObjectsCommand cannot use the TransformBox 120 // anymore 121 _NotifyDeleted(); 122 123 Reset(); 124 SetBox(box); 125 126 fView->UnlockLooper(); 127 } 128 129 // Perform 130 Command* 131 TransformShapesBox::Perform() 132 { 133 return NULL; 134 } 135 136 // Cancel 137 Command* 138 TransformShapesBox::Cancel() 139 { 140 SetTransformation(B_ORIGIN, B_ORIGIN, 0.0, 1.0, 1.0); 141 142 return NULL; 143 } 144 145 // TransformFromCanvas 146 void 147 TransformShapesBox::TransformFromCanvas(BPoint& point) const 148 { 149 fParentTransform.InverseTransform(&point); 150 fCanvasView->ConvertFromCanvas(&point); 151 } 152 153 // TransformToCanvas 154 void 155 TransformShapesBox::TransformToCanvas(BPoint& point) const 156 { 157 fCanvasView->ConvertToCanvas(&point); 158 fParentTransform.Transform(&point); 159 } 160 161 // ZoomLevel 162 float 163 TransformShapesBox::ZoomLevel() const 164 { 165 return fCanvasView->ZoomLevel(); 166 } 167 168 // ViewSpaceRotation 169 double 170 TransformShapesBox::ViewSpaceRotation() const 171 { 172 Transformable t(*this); 173 t.Multiply(fParentTransform); 174 return t.rotation() * 180.0 / PI; 175 } 176 177 // MakeCommand 178 TransformCommand* 179 TransformShapesBox::MakeCommand(const char* commandName, uint32 nameIndex) 180 { 181 const Transformable* objects[fCount]; 182 for (int32 i = 0; i < fCount; i++) 183 objects[i] = fShapes[i]; 184 185 return new TransformObjectsCommand(this, objects, fOriginals, fCount, 186 187 Pivot(), 188 Translation(), 189 LocalRotation(), 190 LocalXScale(), 191 LocalYScale(), 192 193 commandName, 194 nameIndex); 195 } 196 197