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