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