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
28using std::nothrow;
29
30// constructor
31FreezeTransformationCommand::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
66FreezeTransformationCommand::~FreezeTransformationCommand()
67{
68	delete[] fShapes;
69	delete[] fOriginalTransformations;
70}
71
72// InitCheck
73status_t
74FreezeTransformationCommand::InitCheck()
75{
76	return fShapes && fOriginalTransformations ? B_OK : B_NO_INIT;
77}
78
79// Perform
80status_t
81FreezeTransformationCommand::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
95status_t
96FreezeTransformationCommand::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
118void
119FreezeTransformationCommand::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
130void
131FreezeTransformationCommand::_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