2009-11-08 Chris Toshok <toshok@ximian.com>
[moon.git] / src / transform.cpp
blob56dccff9eeed91b0b195ab0277783fc41ae91592
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3 * transform.cpp:
5 * Contact:
6 * Moonlight List (moonlight-list@lists.ximian.com)
8 * Copyright 2007 Novell, Inc. (http://www.novell.com)
10 * See the LICENSE file included with the distribution for details.
13 #include <config.h>
15 #include <math.h>
17 #include "transform.h"
21 // GeneralTransform
24 void
25 GeneralTransform::OnPropertyChanged (PropertyChangedEventArgs *args, MoonError *error)
27 if (args->GetProperty ()->GetOwnerType() == Type::DEPENDENCY_OBJECT) {
28 DependencyObject::OnPropertyChanged (args, error);
29 return;
32 need_update = true;
34 // If the transform changes, we need to notify our owners
35 // that they must repaint (all of our properties have
36 // a visible effect.
38 // There is no need to override this on the base classes
39 // as they are sealed, so no new properties can be added
40 // and I do not believe that we can create new instances
41 // of transform from C#, and in that case, we would only
42 // be slower.
44 NotifyListenersOfPropertyChange (args, error);
47 void
48 GeneralTransform::UpdateTransform ()
50 g_warning ("GeneralTransform::UpdateTransform has been called. The derived class should have overridden it.");
53 void
54 GeneralTransform::MaybeUpdateTransform ()
56 if (need_update) {
57 UpdateTransform ();
58 need_update = false;
62 void
63 GeneralTransform::GetTransform (cairo_matrix_t *value)
65 MaybeUpdateTransform ();
66 *value = _matrix;
69 Matrix*
70 GeneralTransform::GetMatrix ()
72 MaybeUpdateTransform ();
73 return new Matrix (&_matrix);
76 Point
77 GeneralTransform::Transform (Point point)
79 MaybeUpdateTransform ();
80 return point.Transform (&_matrix);
83 void
84 general_transform_transform_point (GeneralTransform *t, Point *p, Point *r)
86 *r = t->Transform (*p);
91 // RotateTransform
94 void
95 RotateTransform::UpdateTransform ()
97 double angle, center_x, center_y;
98 double radians;
100 angle = GetAngle ();
101 center_x = GetCenterX ();
102 center_y = GetCenterY ();
104 radians = angle / 180.0 * M_PI;
106 if (center_x == 0.0 && center_y == 0.0) {
107 cairo_matrix_init_rotate (&_matrix, radians);
109 else {
110 cairo_matrix_init_translate (&_matrix, center_x, center_y);
111 cairo_matrix_rotate (&_matrix, radians);
112 cairo_matrix_translate (&_matrix, -center_x, -center_y);
114 //printf ("Returning2 %g %g %g %g %g %g\n", value->xx, value->yx, value->xy, value->yy, value->x0, value->y0);
119 // TranslateTransform
122 void
123 TranslateTransform::UpdateTransform ()
125 double x = GetX ();
126 double y = GetY ();
128 cairo_matrix_init_translate (&_matrix, x, y);
129 //printf ("translating dx %g dy %g", x, y);
130 //printf ("TranslateTransform %g %g %g %g %g %g\n", value->xx, value->yx, value->xy, value->yy, value->x0, value->y0);
134 // ScaleTransform
136 void
137 ScaleTransform::UpdateTransform ()
139 double sx = GetScaleX ();
140 double sy = GetScaleY ();
142 // XXX you don't want to know. don't make these 0.00001, or
143 // else cairo spits out errors about non-invertable matrices
144 // (or worse, crashes)
146 // the 0.0 scales are caused in at least one instance by us
147 // being too aggressive at starting animations at time=0 when
148 // they're supposed to (unset, or 0:0:0 BeginTime)
150 if (sx == 0.0) sx = 0.00002;
151 if (sy == 0.0) sy = 0.00002;
153 double cx = GetCenterX ();
154 double cy = GetCenterY ();
156 if (cx == 0.0 && cy == 0.0) {
157 cairo_matrix_init_scale (&_matrix, sx, sy);
159 else {
160 cairo_matrix_init_translate (&_matrix, cx, cy);
161 cairo_matrix_scale (&_matrix, sx, sy);
162 cairo_matrix_translate (&_matrix, -cx, -cy);
164 //printf ("scaling sx %g sy %g at center cx %g cy %g\n", sx, sy, cx, cy);
165 //printf ("ScaleTransform %g %g %g %g %g %g\n", value->xx, value->yx, value->xy, value->yy, value->x0, value->y0);
169 // SkewTransform
172 void
173 SkewTransform::UpdateTransform ()
175 double cx = GetCenterX ();
176 double cy = GetCenterY ();
178 bool translation = ((cx != 0.0) || (cy != 0.0));
179 if (translation)
180 cairo_matrix_init_translate (&_matrix, cx, cy);
181 else
182 cairo_matrix_init_identity (&_matrix);
184 double ax = GetAngleX ();
185 if (ax != 0.0)
186 _matrix.xy = tan (ax * M_PI / 180);
188 double ay = GetAngleY ();
189 if (ay != 0.0)
190 _matrix.yx = tan (ay * M_PI / 180);
192 if (translation)
193 cairo_matrix_translate (&_matrix, -cx, -cy);
195 //printf ("SkewTransform %g %g %g %g %g %g\n", value->xx, value->yx, value->xy, value->yy, value->x0, value->y0);
199 // Matrix
202 Matrix::Matrix ()
204 SetObjectType (Type::MATRIX);
205 cairo_matrix_init_identity (&matrix);
208 Matrix::Matrix(cairo_matrix_t *m)
210 SetObjectType (Type::MATRIX);
211 matrix = *m;
212 SetM11 (matrix.xx);
213 SetM12 (matrix.yx);
214 SetM21 (matrix.xy);
215 SetM22 (matrix.yy);
216 SetOffsetX (matrix.x0);
217 SetOffsetY (matrix.y0);
220 void
221 Matrix::OnPropertyChanged (PropertyChangedEventArgs *args, MoonError *error)
223 if (args->GetProperty ()->GetOwnerType() != Type::MATRIX) {
224 DependencyObject::OnPropertyChanged (args, error);
225 return;
228 if (args->GetId () == Matrix::M11Property)
229 matrix.xx = args->GetNewValue()->AsDouble ();
230 else if (args->GetId () == Matrix::M12Property)
231 matrix.yx = args->GetNewValue()->AsDouble ();
232 else if (args->GetId () == Matrix::M21Property)
233 matrix.xy = args->GetNewValue()->AsDouble ();
234 else if (args->GetId () == Matrix::M22Property)
235 matrix.yy = args->GetNewValue()->AsDouble ();
236 else if (args->GetId () == Matrix::OffsetXProperty)
237 matrix.x0 = args->GetNewValue()->AsDouble ();
238 else if (args->GetId () == Matrix::OffsetYProperty)
239 matrix.y0 = args->GetNewValue()->AsDouble ();
241 NotifyListenersOfPropertyChange (args, error);
244 cairo_matrix_t
245 Matrix::GetUnderlyingMatrix ()
247 return matrix;
251 // MatrixTransform
254 void
255 MatrixTransform::OnSubPropertyChanged (DependencyProperty *prop, DependencyObject *obj, PropertyChangedEventArgs *subobj_args)
257 need_update = true;
259 DependencyObject::OnSubPropertyChanged (prop, obj, subobj_args);
261 NotifyListenersOfPropertyChange (MatrixTransform::MatrixProperty, NULL);
264 void
265 MatrixTransform::UpdateTransform ()
267 Matrix *matrix = GetMatrix ();
268 if (matrix)
269 _matrix = matrix->GetUnderlyingMatrix();
270 else
271 cairo_matrix_init_identity (&_matrix);
275 // TransformGroup
278 TransformGroup::TransformGroup ()
280 SetObjectType (Type::TRANSFORMGROUP);
283 void
284 TransformGroup::OnPropertyChanged (PropertyChangedEventArgs *args, MoonError *error)
286 if (args->GetProperty ()->GetOwnerType() != Type::TRANSFORMGROUP) {
287 Transform::OnPropertyChanged (args, error);
288 return;
291 if (args->GetId () == TransformGroup::ChildrenProperty) {
292 need_update = true;
295 NotifyListenersOfPropertyChange (args, error);
298 void
299 TransformGroup::OnCollectionChanged (Collection *col, CollectionChangedEventArgs *args)
301 if (col != GetChildren ()) {
302 Transform::OnCollectionChanged (col, args);
303 return;
306 need_update = true;
307 NotifyListenersOfPropertyChange (TransformGroup::ChildrenProperty, NULL);
310 void
311 TransformGroup::OnCollectionItemChanged (Collection *col, DependencyObject *obj, PropertyChangedEventArgs *args)
313 if (col != GetChildren ()) {
314 Transform::OnCollectionItemChanged (col, obj, args);
315 return;
318 // Unit tests shows that the "cache" matrix value (exposed in SL2) is not updated when child items are changed.
319 // However SL2 does re-compute this value (if dirty) before drawing anything that depends on it.
320 // Currently Moonlight behave differently by always returning the "up to date" matrix
321 need_update = true;
322 NotifyListenersOfPropertyChange (TransformGroup::ChildrenProperty, NULL);
325 void
326 TransformGroup::UpdateTransform ()
328 TransformCollection *children = GetChildren ();
330 cairo_matrix_init_identity (&_matrix);
332 for (int i = 0; i < children->GetCount (); i++) {
333 Transform *transform = children->GetValueAt (i)->AsTransform ();
334 cairo_matrix_t matrix;
336 transform->GetTransform (&matrix);
337 cairo_matrix_multiply (&_matrix, &_matrix, &matrix);