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