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 "TransformShapesBox.h"
10
11#include <new>
12#include <stdio.h>
13#include <string.h>
14
15#include "Shape.h"
16#include "StateView.h"
17#include "TransformObjectsCommand.h"
18
19using std::nothrow;
20
21// constructor
22TransformShapesBox::TransformShapesBox(CanvasView* view,
23									   const Shape** shapes,
24									   int32 count)
25	: CanvasTransformBox(view),
26
27	  fShapes(shapes && count > 0 ? new Shape*[count] : NULL),
28	  fCount(count),
29
30	  fOriginals(NULL),
31
32	  fParentTransform()
33{
34	if (fShapes != NULL) {
35		// allocate storage for the current transformations
36		// of each object
37		fOriginals = new double[fCount * Transformable::matrix_size];
38
39		memcpy(fShapes, shapes, fCount * sizeof(Shape*));
40
41		for (int32 i = 0; i < fCount; i++) {
42			if (fShapes[i]) {
43				fShapes[i]->AcquireReference();
44				fShapes[i]->AddObserver(this);
45			}
46		}
47
48		// trigger init
49		ObjectChanged(fShapes[0]);
50	} else {
51		SetBox(BRect(0, 0, -1, -1));
52	}
53}
54
55// destructor
56TransformShapesBox::~TransformShapesBox()
57{
58	if (fShapes) {
59		for (int32 i = 0; i < fCount; i++) {
60			if (fShapes[i]) {
61				fShapes[i]->RemoveObserver(this);
62				fShapes[i]->ReleaseReference();
63			}
64		}
65		delete[] fShapes;
66	}
67
68	delete[] fOriginals;
69}
70
71// Update
72void
73TransformShapesBox::Update(bool deep)
74{
75	BRect r = Bounds();
76
77	TransformBox::Update(deep);
78
79	BRect dirty(r | Bounds());
80	dirty.InsetBy(-8, -8);
81	fView->Invalidate(dirty);
82
83	if (!deep || !fShapes)
84		return;
85
86	for (int32 i = 0; i < fCount; i++) {
87		if (!fShapes[i])
88			continue;
89
90		fShapes[i]->RemoveObserver(this);
91		fShapes[i]->SuspendNotifications(true);
92
93		// reset the objects transformation to the saved state
94		fShapes[i]->LoadFrom(&fOriginals[i * Transformable::matrix_size]);
95		// combined with the current transformation
96		fShapes[i]->Multiply(*this);
97
98		fShapes[i]->SuspendNotifications(false);
99		fShapes[i]->AddObserver(this);
100	}
101}
102
103// ObjectChanged
104void
105TransformShapesBox::ObjectChanged(const Observable* object)
106{
107	if (!fView->LockLooper())
108		return;
109
110	fParentTransform.Reset();
111	// figure out bounds and store initial transformations
112	BRect box(LONG_MAX, LONG_MAX, LONG_MIN, LONG_MIN);
113	for (int32 i = 0; i < fCount; i++) {
114		if (!fShapes[i])
115			continue;
116
117		box = box | fShapes[i]->Bounds();
118		fShapes[i]->StoreTo(&fOriginals[i * Transformable::matrix_size]);
119	}
120	// any TransformObjectsCommand cannot use the TransformBox
121	// anymore
122	_NotifyDeleted();
123
124	Reset();
125	SetBox(box);
126
127	fView->UnlockLooper();
128}
129
130// MakeCommand
131TransformCommand*
132TransformShapesBox::MakeCommand(const char* commandName)
133{
134	Transformable* objects[fCount];
135	for (int32 i = 0; i < fCount; i++)
136		objects[i] = fShapes[i];
137
138	return new TransformObjectsCommand(this, objects, fOriginals, fCount,
139
140									   Pivot(),
141									   Translation(),
142									   LocalRotation(),
143									   LocalXScale(),
144									   LocalYScale(),
145
146									   commandName);
147}
148
149