xref: /haiku/src/apps/icon-o-matic/shape/commands/FreezeTransformationCommand.cpp (revision c9afad22682e9f15753db4e9ca8684e2d4a643a9)
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 #include <StringFormat.h>
18 
19 #include "GradientTransformable.h"
20 #include "PathSourceShape.h"
21 #include "Style.h"
22 #include "VectorPath.h"
23 
24 
25 #undef B_TRANSLATION_CONTEXT
26 #define B_TRANSLATION_CONTEXT "Icon-O-Matic-FreezeTransformationCmd"
27 
28 
29 using std::nothrow;
30 
31 // constructor
32 FreezeTransformationCommand::FreezeTransformationCommand(
33 								   PathSourceShape** const shapes,
34 								   int32 count)
35 	: Command(),
36 	  fShapes(shapes && count > 0 ? new (nothrow) PathSourceShape*[count] : NULL),
37 	  fOriginalTransformations(count > 0 ? new (nothrow) double[
38 									count * Transformable::matrix_size]
39 							   : NULL),
40 	  fCount(count)
41 {
42 	if (!fShapes || !fOriginalTransformations)
43 		return;
44 
45 	memcpy(fShapes, shapes, sizeof(PathSourceShape*) * fCount);
46 
47 	bool initOk = false;
48 
49 	for (int32 i = 0; i < fCount; i++) {
50 		if (!fShapes[i])
51 			continue;
52 		if (!fShapes[i]->IsIdentity())
53 			initOk = true;
54 		fShapes[i]->StoreTo(&fOriginalTransformations[
55 			i * Transformable::matrix_size]);
56 	}
57 
58 	if (!initOk) {
59 		delete[] fShapes;
60 		fShapes = NULL;
61 		delete[] fOriginalTransformations;
62 		fOriginalTransformations = NULL;
63 	}
64 }
65 
66 // destructor
67 FreezeTransformationCommand::~FreezeTransformationCommand()
68 {
69 	delete[] fShapes;
70 	delete[] fOriginalTransformations;
71 }
72 
73 // InitCheck
74 status_t
75 FreezeTransformationCommand::InitCheck()
76 {
77 	return fShapes && fOriginalTransformations ? B_OK : B_NO_INIT;
78 }
79 
80 // Perform
81 status_t
82 FreezeTransformationCommand::Perform()
83 {
84 	for (int32 i = 0; i < fCount; i++) {
85 		if (!fShapes[i] || fShapes[i]->IsIdentity())
86 			continue;
87 
88 		_ApplyTransformation(fShapes[i], *(fShapes[i]));
89 		fShapes[i]->Reset();
90 	}
91 
92 	return B_OK;
93 }
94 
95 // Undo
96 status_t
97 FreezeTransformationCommand::Undo()
98 {
99 	for (int32 i = 0; i < fCount; i++) {
100 		if (!fShapes[i])
101 			continue;
102 
103 		// restore original transformation
104 		fShapes[i]->LoadFrom(&fOriginalTransformations[
105 			i * Transformable::matrix_size]);
106 
107 		Transformable transform(*(fShapes[i]));
108 		if (!transform.IsValid() || transform.IsIdentity())
109 			continue;
110 
111 		transform.Invert();
112 		_ApplyTransformation(fShapes[i], transform);
113 	}
114 
115 	return B_OK;
116 }
117 
118 // GetName
119 void
120 FreezeTransformationCommand::GetName(BString& name)
121 {
122 	static BStringFormat format(B_TRANSLATE("Freeze {0, plural, "
123 		"one{shape} other{shapes}}"));
124 	format.Format(name, fCount);
125 }
126 
127 // #pragma mark -
128 
129 // _ApplyTransformation
130 void
131 FreezeTransformationCommand::_ApplyTransformation(PathSourceShape* shape,
132 									const Transformable& transform)
133 {
134 	// apply inverse of old shape transformation to every assigned path
135 	int32 pathCount = shape->Paths()->CountItems();
136 	for (int32 i = 0; i < pathCount; i++) {
137 		VectorPath* path = shape->Paths()->ItemAtFast(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 %" B_PRId32 " 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