xref: /haiku/src/apps/icon-o-matic/shape/commands/FreezeTransformationCommand.cpp (revision 55b40aa53a835472ec7952b138ae4256203d02e4)
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 "FreezeTransformationCommand.h"
10 
11 #include <new>
12 #include <stdio.h>
13 #include <string.h>
14 
15 #include "Gradient.h"
16 #include "Shape.h"
17 #include "Style.h"
18 #include "VectorPath.h"
19 
20 using std::nothrow;
21 
22 // constructor
23 FreezeTransformationCommand::FreezeTransformationCommand(
24 								   Shape** const shapes,
25 								   int32 count)
26 	: Command(),
27 	  fShapes(shapes && count > 0 ? new (nothrow) Shape*[count] : NULL),
28 	  fOriginalTransformations(count > 0 ? new (nothrow) double[
29 									count * Transformable::matrix_size]
30 							   : NULL),
31 	  fCount(count)
32 {
33 	if (!fShapes || !fOriginalTransformations)
34 		return;
35 
36 	memcpy(fShapes, shapes, sizeof(Shape*) * fCount);
37 
38 	bool initOk = false;
39 
40 	for (int32 i = 0; i < fCount; i++) {
41 		if (!fShapes[i])
42 			continue;
43 		if (!fShapes[i]->IsIdentity())
44 			initOk = true;
45 		fShapes[i]->StoreTo(&fOriginalTransformations[
46 			i * Transformable::matrix_size]);
47 	}
48 
49 	if (!initOk) {
50 		delete[] fShapes;
51 		fShapes = NULL;
52 		delete[] fOriginalTransformations;
53 		fOriginalTransformations = NULL;
54 	}
55 }
56 
57 // destructor
58 FreezeTransformationCommand::~FreezeTransformationCommand()
59 {
60 	delete[] fShapes;
61 	delete[] fOriginalTransformations;
62 }
63 
64 // InitCheck
65 status_t
66 FreezeTransformationCommand::InitCheck()
67 {
68 	return fShapes && fOriginalTransformations ? B_OK : B_NO_INIT;
69 }
70 
71 // Perform
72 status_t
73 FreezeTransformationCommand::Perform()
74 {
75 	for (int32 i = 0; i < fCount; i++) {
76 		if (!fShapes[i] || fShapes[i]->IsIdentity())
77 			continue;
78 
79 		_ApplyTransformation(fShapes[i], *(fShapes[i]));
80 		fShapes[i]->Reset();
81 	}
82 
83 	return B_OK;
84 }
85 
86 // Undo
87 status_t
88 FreezeTransformationCommand::Undo()
89 {
90 	for (int32 i = 0; i < fCount; i++) {
91 		if (!fShapes[i])
92 			continue;
93 
94 		// restore original transformation
95 		fShapes[i]->LoadFrom(&fOriginalTransformations[
96 			i * Transformable::matrix_size]);
97 
98 		Transformable transform(*(fShapes[i]));
99 		if (!transform.IsValid() || transform.IsIdentity())
100 			continue;
101 
102 		transform.Invert();
103 		_ApplyTransformation(fShapes[i], transform);
104 	}
105 
106 	return B_OK;
107 }
108 
109 // GetName
110 void
111 FreezeTransformationCommand::GetName(BString& name)
112 {
113 	if (fCount > 1)
114 		name << "Freeze Shapes";
115 	else
116 		name << "Freeze Shape";
117 }
118 
119 // #pragma mark -
120 
121 // _ApplyTransformation
122 void
123 FreezeTransformationCommand::_ApplyTransformation(Shape* shape,
124 									const Transformable& transform)
125 {
126 	// apply inverse of old shape transformation to every assigned path
127 	int32 pathCount = shape->Paths()->CountPaths();
128 	for (int32 i = 0; i < pathCount; i++) {
129 		VectorPath* path = shape->Paths()->PathAtFast(i);
130 		int32 shapes = 0;
131 		int32 listeners = path->CountListeners();
132 		for (int32 j = 0; j < listeners; j++) {
133 			if (dynamic_cast<Shape*>(path->ListenerAtFast(j)))
134 				shapes++;
135 		}
136 		// only freeze transformation of path if only one
137 		// shape has it assigned
138 		if (shapes == 1) {
139 			path->ApplyTransform(transform);
140 		} else {
141 			printf("Not transfering transformation of \"%s\" onto "
142 				   "path \"%s\", because %ld other shapes "
143 				   "have it assigned.\n", shape->Name(), path->Name(),
144 				   shapes - 1);
145 		}
146 	}
147 	// take care of style too
148 	if (shape->Style() && shape->Style()->Gradient()) {
149 		// TODO: not if more than one shape have this style assigned!
150 		shape->Style()->Gradient()->Multiply(transform);
151 	}
152 }
153