xref: /haiku/src/apps/icon-o-matic/transformable/TransformShapesBox.cpp (revision 9ecf9d1c1d4888d341a6eac72112c72d1ae3a4cb)
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