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 19using std::nothrow; 20 21// constructor 22TransformShapesBox::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]->AcquireReference(); 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 56TransformShapesBox::~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]->ReleaseReference(); 63 } 64 } 65 delete[] fShapes; 66 } 67 68 delete[] fOriginals; 69} 70 71// Update 72void 73TransformShapesBox::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 104void 105TransformShapesBox::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 131TransformCommand* 132TransformShapesBox::MakeCommand(const char* commandName) 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} 148 149