xref: /haiku/src/apps/icon-o-matic/transformable/TransformShapesBox.cpp (revision 302f62604763c95777d6d04cca456e876f471c4f)
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) {
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]->AddObserver(this);
44 		}
45 
46 		// trigger init
47 		ObjectChanged(fShapes[0]);
48 	} else {
49 		SetBox(BRect(0, 0, -1, -1));
50 	}
51 }
52 
53 // destructor
54 TransformShapesBox::~TransformShapesBox()
55 {
56 	if (fShapes) {
57 		for (int32 i = 0; i < fCount; i++) {
58 			if (fShapes[i])
59 				fShapes[i]->RemoveObserver(this);
60 		}
61 		delete[] fShapes;
62 	}
63 
64 	delete[] fOriginals;
65 }
66 
67 // Update
68 void
69 TransformShapesBox::Update(bool deep)
70 {
71 	BRect r = Bounds();
72 
73 	TransformBox::Update(deep);
74 
75 	BRect dirty(r | Bounds());
76 	dirty.InsetBy(-8, -8);
77 	fView->Invalidate(dirty);
78 
79 	if (!deep || !fShapes)
80 		return;
81 
82 	for (int32 i = 0; i < fCount; i++) {
83 		if (!fShapes[i])
84 			continue;
85 
86 		fShapes[i]->RemoveObserver(this);
87 		fShapes[i]->SuspendNotifications(true);
88 
89 		// reset the objects transformation to the saved state
90 		fShapes[i]->LoadFrom(&fOriginals[i * Transformable::matrix_size]);
91 		// combined with the current transformation
92 		fShapes[i]->Multiply(*this);
93 
94 		fShapes[i]->SuspendNotifications(false);
95 		fShapes[i]->AddObserver(this);
96 	}
97 }
98 
99 // ObjectChanged
100 void
101 TransformShapesBox::ObjectChanged(const Observable* object)
102 {
103 	if (!fView->LockLooper())
104 		return;
105 
106 	fParentTransform.Reset();
107 	// figure out bounds and store initial transformations
108 	BRect box(LONG_MAX, LONG_MAX, LONG_MIN, LONG_MIN);
109 	for (int32 i = 0; i < fCount; i++) {
110 		if (!fShapes[i])
111 			continue;
112 
113 		box = box | fShapes[i]->Bounds();
114 		fShapes[i]->StoreTo(&fOriginals[i * Transformable::matrix_size]);
115 	}
116 	// any TransformObjectsCommand cannot use the TransformBox
117 	// anymore
118 	_NotifyDeleted();
119 
120 	Reset();
121 	SetBox(box);
122 
123 	fView->UnlockLooper();
124 }
125 
126 // MakeCommand
127 TransformCommand*
128 TransformShapesBox::MakeCommand(const char* commandName, uint32 nameIndex)
129 {
130 	Transformable* objects[fCount];
131 	for (int32 i = 0; i < fCount; i++)
132 		objects[i] = fShapes[i];
133 
134 	return new TransformObjectsCommand(this, objects, fOriginals, fCount,
135 
136 									   Pivot(),
137 									   Translation(),
138 									   LocalRotation(),
139 									   LocalXScale(),
140 									   LocalYScale(),
141 
142 									   commandName,
143 									   nameIndex);
144 }
145 
146