File: | home/HaikuArchives/ArtPaint/artpaint/viewmanipulators/RotationManipulator.cpp |
Warning: | line 382, column 12 Although the value stored to 'green' is used in the enclosing expression, the value is never actually read from 'green' |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* |
2 | * Copyright 2003, Heikki Suhonen |
3 | * Distributed under the terms of the MIT License. |
4 | * |
5 | * Authors: |
6 | * Heikki Suhonen <heikki.suhonen@gmail.com> |
7 | * Dale Cieslak <dcieslak@yahoo.com> |
8 | * |
9 | */ |
10 | |
11 | #include "HSPolygon.h" |
12 | #include "ImageView.h" |
13 | #include "MessageConstants.h" |
14 | #include "PixelOperations.h" |
15 | #include "RotationManipulator.h" |
16 | #include "Selection.h" |
17 | |
18 | |
19 | #include <Catalog.h> |
20 | #include <ClassInfo.h> |
21 | #include <LayoutBuilder.h> |
22 | #include <StatusBar.h> |
23 | #include <TextControl.h> |
24 | #include <Window.h> |
25 | |
26 | |
27 | #include <ctype.h> |
28 | #include <math.h> |
29 | #include <new> |
30 | #include <stdio.h> |
31 | #include <stdlib.h> |
32 | #include <string.h> |
33 | |
34 | |
35 | #undef B_TRANSLATION_CONTEXT"Manipulators" |
36 | #define B_TRANSLATION_CONTEXT"Manipulators" "Manipulators" |
37 | |
38 | |
39 | #define PI3.14159265358979323846 M_PI3.14159265358979323846 |
40 | |
41 | |
42 | RotationManipulator::RotationManipulator(BBitmap *bitmap) |
43 | : WindowGUIManipulator() |
44 | { |
45 | settings = new RotationManipulatorSettings(); |
46 | config_view = NULL__null; |
47 | preview_bitmap = NULL__null; |
48 | copy_of_the_preview_bitmap = NULL__null; |
49 | |
50 | SetPreviewBitmap(bitmap); |
51 | |
52 | last_calculated_resolution = 0; |
53 | |
54 | BPoint poly_points[8]; |
55 | poly_points[0] = BPoint(-5,0); |
56 | poly_points[1] = BPoint(0,0); |
57 | poly_points[2] = BPoint(0,-5); |
58 | poly_points[3] = BPoint(0,0); |
59 | poly_points[4] = BPoint(5,0); |
60 | poly_points[5] = BPoint(0,0); |
61 | poly_points[6] = BPoint(0,5); |
62 | poly_points[7] = BPoint(0,0); |
63 | |
64 | view_polygon = new HSPolygon(poly_points,8); |
65 | } |
66 | |
67 | |
68 | |
69 | RotationManipulator::~RotationManipulator() |
70 | { |
71 | delete copy_of_the_preview_bitmap; |
72 | delete view_polygon; |
73 | |
74 | if (config_view != NULL__null) { |
75 | config_view->RemoveSelf(); |
76 | delete config_view; |
77 | } |
78 | } |
79 | |
80 | |
81 | void RotationManipulator::SetPreviewBitmap(BBitmap *bitmap) |
82 | { |
83 | if (config_view != NULL__null) { |
84 | config_view->SetAngle(0.0); |
85 | } |
86 | |
87 | if ((bitmap == NULL__null) || (preview_bitmap == NULL__null) || (bitmap->Bounds() != preview_bitmap->Bounds())) { |
88 | try { |
89 | if (preview_bitmap != NULL__null) { |
90 | delete copy_of_the_preview_bitmap; |
91 | } |
92 | if (bitmap != NULL__null) { |
93 | preview_bitmap = bitmap; |
94 | copy_of_the_preview_bitmap = DuplicateBitmap(preview_bitmap); |
95 | BRect bounds = preview_bitmap->Bounds(); |
96 | settings->origo = BPoint((bounds.right-bounds.left)/2+bounds.left,(bounds.bottom-bounds.top)/2+bounds.top); |
97 | } |
98 | else { |
99 | preview_bitmap = NULL__null; |
100 | copy_of_the_preview_bitmap = NULL__null; |
101 | } |
102 | } |
103 | catch (std::bad_alloc e) { |
104 | preview_bitmap = NULL__null; |
105 | copy_of_the_preview_bitmap=NULL__null; |
106 | throw e; |
107 | } |
108 | } |
109 | else { |
110 | // Just update the copy_of_the_preview_bitmap |
111 | preview_bitmap = bitmap; |
112 | uint32 *source = (uint32*)preview_bitmap->Bits(); |
113 | uint32 *target = (uint32*)copy_of_the_preview_bitmap->Bits(); |
114 | int32 bitslength = min_c(preview_bitmap->BitsLength(),copy_of_the_preview_bitmap->BitsLength())((preview_bitmap->BitsLength())>(copy_of_the_preview_bitmap ->BitsLength())?(copy_of_the_preview_bitmap->BitsLength ()):(preview_bitmap->BitsLength())); |
115 | memcpy(target,source,bitslength); |
116 | } |
117 | |
118 | if (preview_bitmap != NULL__null) { |
119 | double speed = GetSystemClockSpeed() / 15000; |
120 | |
121 | BRect bounds = preview_bitmap->Bounds(); |
122 | float num_pixels = (bounds.Width()+1) * (bounds.Height() + 1); |
123 | lowest_available_quality = 1; |
124 | while ((2*num_pixels/lowest_available_quality/lowest_available_quality) > speed) |
125 | lowest_available_quality *= 2; |
126 | |
127 | highest_available_quality = max_c(lowest_available_quality/2,1)((lowest_available_quality/2)>(1)?(lowest_available_quality /2):(1)); |
128 | } |
129 | else { |
130 | lowest_available_quality = 1; |
131 | highest_available_quality = 1; |
132 | } |
133 | last_calculated_resolution = lowest_available_quality; |
134 | } |
135 | |
136 | |
137 | BRegion RotationManipulator::Draw(BView *view,float mag_scale) |
138 | { |
139 | float x = settings->origo.x; |
140 | float y = settings->origo.y; |
141 | |
142 | view->StrokeLine(BPoint(mag_scale*x-10,mag_scale*y),BPoint(mag_scale*x+10,mag_scale*y),B_MIXED_COLORS); |
143 | view->StrokeLine(BPoint(mag_scale*x,mag_scale*y-10),BPoint(mag_scale*x,mag_scale*y+10),B_MIXED_COLORS); |
144 | view->StrokeEllipse(BRect(BPoint(mag_scale*x-5,mag_scale*y-5),BPoint(mag_scale*x+5,mag_scale*y+5)),B_MIXED_COLORS); |
145 | |
146 | BRegion updated_region; |
147 | updated_region.Set(BRect(mag_scale*x-10,mag_scale*y-10,mag_scale*x+10,mag_scale*y+10)); |
148 | return updated_region; |
149 | } |
150 | |
151 | |
152 | void RotationManipulator::MouseDown(BPoint point,uint32 buttons,BView*,bool first_click) |
153 | { |
154 | if (first_click == TRUE1) { |
155 | if (!(buttons & B_PRIMARY_MOUSE_BUTTON) || ((fabs(point.x-settings->origo.x)<10) && (fabs(point.y-settings->origo.y)<10))) |
156 | move_origo = TRUE1; |
157 | else |
158 | move_origo = FALSE0; |
159 | } |
160 | |
161 | if (!move_origo) { |
162 | // Here we calculate the new angle |
163 | previous_angle = settings->angle; |
164 | float new_angle; |
165 | |
166 | float dy = point.y - settings->origo.y; |
167 | float dx = point.x - settings->origo.x; |
168 | new_angle = atan2(dy,dx); |
169 | new_angle = new_angle / PI3.14159265358979323846 *180; |
170 | if (first_click == TRUE1) { |
171 | starting_angle = new_angle; |
172 | } |
173 | else { |
174 | settings->angle += new_angle - starting_angle; |
175 | starting_angle = new_angle; |
176 | if ((config_view != NULL__null) && (new_angle != previous_angle)) { |
177 | config_view->SetAngle(settings->angle); |
178 | } |
179 | } |
180 | } |
181 | else { |
182 | // Set the new origo for rotation and reset the angle. |
183 | previous_angle = settings->angle; |
184 | settings->angle = 0; |
185 | |
186 | settings->origo = point; |
187 | } |
188 | } |
189 | |
190 | |
191 | BBitmap* RotationManipulator::ManipulateBitmap(ManipulatorSettings *set,BBitmap *original,Selection *selection,BStatusBar *status_bar) |
192 | { |
193 | // Here move the contents of the original-bitmap to the new_bitmap, |
194 | // rotated by s->angle around s->origin. |
195 | RotationManipulatorSettings *new_settings = cast_as(set,RotationManipulatorSettings)(dynamic_cast<RotationManipulatorSettings*>(set)); |
196 | if (new_settings == NULL__null) |
197 | return NULL__null; |
198 | |
199 | if (original == NULL__null) |
200 | return NULL__null; |
201 | |
202 | if (new_settings->angle == 0) |
203 | return NULL__null; |
204 | |
205 | BBitmap *new_bitmap; |
206 | if (original != preview_bitmap) { |
207 | original->Lock(); |
208 | BRect bitmap_frame = original->Bounds(); |
209 | new_bitmap = new BBitmap(bitmap_frame,B_RGB32); |
210 | original->Unlock(); |
211 | if (new_bitmap->IsValid() == FALSE0) |
212 | throw std::bad_alloc(); |
213 | } |
214 | else { |
215 | new_bitmap = original; |
216 | original = copy_of_the_preview_bitmap; |
217 | } |
218 | |
219 | // We should calculate the new pixel value as weighted average from the |
220 | // four pixels that will be under the inverse-rotated pixel. |
221 | // |
222 | // X X When inverse rotated from new bitmap, |
223 | // X X the pixel will cover four pixels, each |
224 | // with a different weight. |
225 | // |
226 | BPoint center = new_settings->origo; |
227 | |
228 | float the_angle = new_settings->angle; |
229 | float sin_angle = sin(-the_angle/360*2*PI3.14159265358979323846); |
230 | float cos_angle = cos(-the_angle/360*2*PI3.14159265358979323846); |
231 | |
232 | int32 *target_bits = (int32*)new_bitmap->Bits(); |
233 | int32 *source_bits = (int32*)original->Bits(); |
234 | int32 source_bpr = original->BytesPerRow()/4; |
235 | int32 target_bpr = new_bitmap->BytesPerRow()/4; |
236 | |
237 | // copy the points according to angle |
238 | float height = new_bitmap->Bounds().Height(); |
239 | float width = new_bitmap->Bounds().Width(); |
240 | float left = original->Bounds().left; |
241 | float right = original->Bounds().right; |
242 | float top = original->Bounds().top; |
243 | float bottom = original->Bounds().bottom; |
244 | float center_x = center.x; |
245 | float center_y = center.y; |
246 | float source_x,source_y; |
247 | float y_times_sin = (-center_y)*sin_angle; |
248 | float y_times_cos = (-center_y)*cos_angle; |
249 | |
250 | BWindow *status_bar_window = status_bar->Window(); |
251 | |
252 | float red,green,blue,alpha; // before optimization was int32 |
253 | |
254 | float floor_x,ceil_x,floor_y,ceil_y; // was int32 before optimization |
255 | |
256 | uint32 p1,p2,p3,p4; |
257 | |
258 | union { |
259 | uint8 bytes[4]; |
260 | uint32 word; |
261 | } background; |
262 | // Transparent background. |
263 | background.bytes[0] = 0xFF; |
264 | background.bytes[1] = 0xFF; |
265 | background.bytes[2] = 0xFF; |
266 | background.bytes[3] = 0x00; |
267 | |
268 | if (selection->IsEmpty()) { |
269 | for (float y=0;y<=height;y++) { |
270 | float x_times_sin = (-center_x)*sin_angle; |
271 | float x_times_cos = (-center_x)*cos_angle; |
272 | for (float x=0;x<=width;x++) { |
273 | // rotate here around the origin |
274 | source_x = x_times_cos - y_times_sin; |
275 | source_y = x_times_sin + y_times_cos; |
276 | // translate back to correct position |
277 | source_x += center_x; |
278 | source_y += center_y; |
279 | |
280 | floor_x = floor(source_x); |
281 | ceil_x = floor_x + 1; |
282 | floor_y = floor(source_y); |
283 | ceil_y = floor_y + 1; |
284 | |
285 | red = green = blue = alpha = 0; |
286 | |
287 | float u = source_x - floor_x; |
288 | float v = source_y - floor_y; |
289 | // Then add the weighted sums of the four pixels. |
290 | if (( floor_x <= right) && (floor_y <= bottom) |
291 | && (floor_x>=left) && (floor_y>=top)) { |
292 | p1 = *(source_bits + (int32)floor_x + (int32)floor_y*source_bpr); |
293 | } |
294 | else { |
295 | p1 = background.word; |
296 | } |
297 | |
298 | if (( ceil_x <= right) && (floor_y <= bottom) |
299 | && (ceil_x>=left) && (floor_y>=top)) { |
300 | p2 = *(source_bits + (int32)ceil_x + (int32)floor_y*source_bpr); |
301 | } |
302 | else { |
303 | p2 = background.word; |
304 | } |
305 | |
306 | if (( floor_x <= right) && (ceil_y <= bottom) |
307 | && (floor_x>=left) && (ceil_y>=top)) { |
308 | p3 = *(source_bits + (int32)floor_x + (int32)ceil_y*source_bpr); |
309 | } |
310 | else { |
311 | p3 = background.word; |
312 | } |
313 | |
314 | if (( ceil_x <= right) && (ceil_y <= bottom) |
315 | && (ceil_x>=left) && (ceil_y>=top)) { |
316 | p4 = *(source_bits + (int32)ceil_x + (int32)ceil_y*source_bpr); |
317 | } |
318 | else { |
319 | p4 = background.word; |
320 | } |
321 | |
322 | *target_bits++ = bilinear_interpolation(p1,p2,p3,p4,u,v); |
323 | x_times_sin += sin_angle; |
324 | x_times_cos += cos_angle; |
325 | } |
326 | y_times_sin += sin_angle; |
327 | y_times_cos += cos_angle; |
328 | if ((((int32)y % 20) == 0) && (status_bar != NULL__null) && (status_bar_window != NULL__null)) { |
329 | status_bar_window->Lock(); |
330 | status_bar->Update(100.0/(float)height*20); |
331 | status_bar_window->Unlock(); |
332 | } |
333 | } |
334 | } |
335 | else { |
336 | // This should be done by first rotating the selection and then looking up what pixels |
337 | // of original image correspond to the pixels in the rotated selection. The only problem |
338 | // with this approach is if we want to clear the selection first so we must clear it before |
339 | // rotating the selection. |
340 | // selection->Recalculate(); |
341 | for (int32 y=0;y<=height;y++) { |
342 | for (int32 x=0;x<=width;x++) { |
343 | if (selection->ContainsPoint(x,y)) |
344 | *(target_bits + x + y*target_bpr) = background.word; |
345 | else |
346 | *(target_bits + x + y*target_bpr) = *(source_bits + x + y*source_bpr); |
347 | } |
348 | } |
349 | |
350 | |
351 | // We must make a copy of the selection in order to be able to rotate it |
352 | // Selection *new_selection = new Selection(selection); |
353 | // new_selection->RotateTo(new_settings->origo,new_settings->angle); |
354 | // new_selection->Recalculate(); |
355 | selection->Recalculate(); |
356 | |
357 | BRect selection_bounds = selection->GetBoundingRect(); |
358 | selection_bounds.PrintToStream(); |
359 | int32 sel_top = (int32)selection_bounds.top; |
360 | int32 sel_bottom = (int32)selection_bounds.bottom; |
361 | int32 sel_left = (int32)selection_bounds.left; |
362 | int32 sel_right = (int32)selection_bounds.right; |
363 | y_times_sin = (sel_top-center_y)*sin_angle; |
364 | y_times_cos = (sel_top-center_y)*cos_angle; |
365 | for (float y=sel_top;y<=sel_bottom;y++) { |
366 | float x_times_sin = (sel_left-center_x)*sin_angle; |
367 | float x_times_cos = (sel_left-center_x)*cos_angle; |
368 | for (float x=sel_left;x<=sel_right;x++) { |
369 | if (selection->ContainsPoint(int32(x), int32(y))) { |
370 | // rotate here around the origin |
371 | source_x = x_times_cos - y_times_sin; |
372 | source_y = x_times_sin + y_times_cos; |
373 | // translate back to correct position |
374 | source_x += center_x; |
375 | source_y += center_y; |
376 | |
377 | floor_x = floor(source_x); |
378 | ceil_x = floor_x + 1; |
379 | floor_y = floor(source_y); |
380 | ceil_y = floor_y + 1; |
381 | |
382 | red = green = blue = alpha = 0; |
Although the value stored to 'green' is used in the enclosing expression, the value is never actually read from 'green' | |
383 | |
384 | float u = source_x - floor_x; |
385 | float v = source_y - floor_y; |
386 | // Then add the weighted sums of the four pixels. |
387 | if (( floor_x <= right) && (floor_y <= bottom) |
388 | && (floor_x>=left) && (floor_y>=top) ) { |
389 | p1 = *(source_bits + (int32)floor_x + (int32)floor_y*source_bpr); |
390 | } |
391 | else { |
392 | p1 = background.word; |
393 | } |
394 | |
395 | // second |
396 | if (( ceil_x <= right) && (floor_y <= bottom) |
397 | && (ceil_x>=left) && (floor_y>=top) ) { |
398 | p2 = *(source_bits + (int32)ceil_x + (int32)floor_y*source_bpr); |
399 | } |
400 | else { |
401 | p2 = background.word; |
402 | } |
403 | |
404 | // third |
405 | if (( floor_x <= right) && (ceil_y <= bottom) |
406 | && (floor_x>=left) && (ceil_y>=top) ) { |
407 | p3 = *(source_bits + (int32)floor_x + (int32)ceil_y*source_bpr); |
408 | } |
409 | else { |
410 | p3 = background.word; |
411 | } |
412 | |
413 | // fourth |
414 | if (( ceil_x <= right) && (ceil_y <= bottom) |
415 | && (ceil_x>=left) && (ceil_y>=top) ) { |
416 | p4 = *(source_bits + (int32)ceil_x + (int32)ceil_y*source_bpr); |
417 | } |
418 | else { |
419 | p4 = background.word; |
420 | } |
421 | |
422 | *(target_bits + (int32)x + (int32)y*target_bpr) = bilinear_interpolation(p1,p2,p3,p4,u,v); |
423 | |
424 | } |
425 | x_times_sin += sin_angle; |
426 | x_times_cos += cos_angle; |
427 | } |
428 | y_times_sin += sin_angle; |
429 | y_times_cos += cos_angle; |
430 | if ((status_bar != NULL__null) && (status_bar->Window() != NULL__null)) { |
431 | BMessage *a_message = new BMessage(B_UPDATE_STATUS_BAR); |
432 | a_message->AddFloat("delta",100.0/(float)(sel_bottom-sel_top)); |
433 | status_bar->Window()->PostMessage(a_message,status_bar); |
434 | delete a_message; |
435 | } |
436 | } |
437 | } |
438 | |
439 | return new_bitmap; |
440 | } |
441 | |
442 | |
443 | int32 RotationManipulator::PreviewBitmap(Selection *selection,bool full_quality,BRegion *updated_region) |
444 | { |
445 | // First decide the resolution of the bitmap |
446 | if ((previous_angle == settings->angle) && (full_quality == FALSE0)) { |
447 | if (last_calculated_resolution <= highest_available_quality) { |
448 | last_calculated_resolution = 0; |
449 | if (previous_origo != settings->origo) { |
450 | previous_origo = settings->origo; |
451 | return DRAW_ONLY_GUI; |
452 | } |
453 | else |
454 | return 0; |
455 | } |
456 | else |
457 | last_calculated_resolution = last_calculated_resolution / 2; |
458 | } |
459 | else if (full_quality == TRUE1) { |
460 | last_calculated_resolution = 1; |
461 | } |
462 | else |
463 | last_calculated_resolution = lowest_available_quality; |
464 | |
465 | |
466 | union { |
467 | uint8 bytes[4]; |
468 | uint32 word; |
469 | } background; |
470 | // Transparent background. |
471 | background.bytes[0] = 0xFF; |
472 | background.bytes[1] = 0xFF; |
473 | background.bytes[2] = 0xFF; |
474 | background.bytes[3] = 0x00; |
475 | |
476 | |
477 | // Then calculate the preview |
478 | BPoint center = settings->origo; |
479 | float the_angle = settings->angle; |
480 | float sin_angle = sin(-the_angle/360*2*PI3.14159265358979323846); |
481 | float cos_angle = cos(-the_angle/360*2*PI3.14159265358979323846); |
482 | |
483 | int32 *target_bits = (int32*)preview_bitmap->Bits(); |
484 | int32 *source_bits = (int32*)copy_of_the_preview_bitmap->Bits(); |
485 | int32 source_bpr = copy_of_the_preview_bitmap->BytesPerRow()/4; |
486 | int32 target_bpr = preview_bitmap->BytesPerRow()/4; |
487 | |
488 | // copy the points according to angle |
489 | float height = preview_bitmap->Bounds().Height(); |
490 | float width = preview_bitmap->Bounds().Width(); |
491 | float left = copy_of_the_preview_bitmap->Bounds().left; |
492 | float right = copy_of_the_preview_bitmap->Bounds().right; |
493 | float top = copy_of_the_preview_bitmap->Bounds().top; |
494 | float bottom = copy_of_the_preview_bitmap->Bounds().bottom; |
495 | float center_x = center.x; |
496 | float center_y = center.y; |
497 | float source_x,source_y; |
498 | float y_times_sin = (-center_y)*sin_angle; |
499 | float y_times_cos = (-center_y)*cos_angle; |
500 | if (selection->IsEmpty()) { |
501 | for (int32 y=0;y<=height;y += last_calculated_resolution) { |
502 | float x_times_sin = (-center_x)*sin_angle; |
503 | float x_times_cos = (-center_x)*cos_angle; |
504 | for (int32 x=0;x<=width;x += last_calculated_resolution) { |
505 | // rotete here around the origin |
506 | source_x = x_times_cos - y_times_sin; |
507 | source_y = x_times_sin + y_times_cos; |
508 | // translate back to correct position |
509 | source_x += center_x; |
510 | source_y += center_y; |
511 | if ((source_x <= right) && (source_y <= bottom) |
512 | && (source_x >= left) && (source_y >= top)) { |
513 | *(target_bits + x + y*target_bpr) = |
514 | *(source_bits + (int32)source_x + (int32)source_y*source_bpr); |
515 | } |
516 | else |
517 | *(target_bits + x + y*target_bpr) = background.word; // Transparent. |
518 | |
519 | x_times_sin += last_calculated_resolution*sin_angle; |
520 | x_times_cos += last_calculated_resolution*cos_angle; |
521 | } |
522 | y_times_sin += last_calculated_resolution*sin_angle; |
523 | y_times_cos += last_calculated_resolution*cos_angle; |
524 | } |
525 | } |
526 | else { |
527 | // Rotate the selection also |
528 | selection->RotateTo(center,the_angle); |
529 | for (int32 y=0;y<=height;y += last_calculated_resolution) { |
530 | float x_times_sin = (-center_x)*sin_angle; |
531 | float x_times_cos = (-center_x)*cos_angle; |
532 | for (int32 x=0;x<=width;x += last_calculated_resolution) { |
533 | // rotete here around the origin |
534 | source_x = x_times_cos - y_times_sin; |
535 | source_y = x_times_sin + y_times_cos; |
536 | // translate back to correct position |
537 | source_x += center_x; |
538 | source_y += center_y; |
539 | if ((source_x <= right) && (source_y <= bottom) |
540 | && (source_x >= left) && (source_y >= top) |
541 | && selection->ContainsPoint(int32(source_x), int32(source_y))) { |
542 | *(target_bits + x + y*target_bpr) = |
543 | *(source_bits + (int32)source_x + (int32)source_y*source_bpr); |
544 | } |
545 | else if (selection->ContainsPoint(BPoint(source_x,source_y))) |
546 | *(target_bits + x + y*target_bpr) = background.word; // Transparent. |
547 | else if (selection->ContainsPoint(x,y)) |
548 | *(target_bits + x + y*target_bpr) = background.word; |
549 | else |
550 | *(target_bits + x + y*target_bpr) = *(source_bits + (int32)x + (int32)y*source_bpr); |
551 | |
552 | x_times_sin += last_calculated_resolution*sin_angle; |
553 | x_times_cos += last_calculated_resolution*cos_angle; |
554 | } |
555 | y_times_sin += last_calculated_resolution*sin_angle; |
556 | y_times_cos += last_calculated_resolution*cos_angle; |
557 | } |
558 | } |
559 | |
560 | updated_region->Set(preview_bitmap->Bounds()); |
561 | |
562 | return last_calculated_resolution; |
563 | } |
564 | |
565 | |
566 | void RotationManipulator::Reset(Selection *selection) |
567 | { |
568 | selection->RotateTo(settings->origo,0); |
569 | settings->angle = 0; |
570 | previous_angle = 0; |
571 | |
572 | if (copy_of_the_preview_bitmap != NULL__null) { |
573 | // memcpy seems to be about 10-15% faster that copying with loop. |
574 | uint32 *source = (uint32*)copy_of_the_preview_bitmap->Bits(); |
575 | uint32 *target = (uint32*)preview_bitmap->Bits(); |
576 | uint32 bits_length = preview_bitmap->BitsLength(); |
577 | |
578 | memcpy(target,source,bits_length); |
579 | } |
580 | } |
581 | |
582 | |
583 | BView* |
584 | RotationManipulator::MakeConfigurationView(const BMessenger& target) |
585 | { |
586 | //if (config_view) |
587 | // return config_view; |
588 | |
589 | config_view = |
590 | new RotationManipulatorConfigurationView(this, target); |
591 | config_view->SetAngle(settings->angle); |
592 | return config_view; |
593 | } |
594 | |
595 | |
596 | void |
597 | RotationManipulator::SetAngle(float angle) |
598 | { |
599 | previous_angle = settings->angle; |
600 | settings->angle = angle; |
601 | } |
602 | |
603 | |
604 | const char* |
605 | RotationManipulator::ReturnHelpString() |
606 | { |
607 | return B_TRANSLATE("Use the primary mouse-button to rotate, other buttons to set the rotation center.")BLocaleRoster::Default()->GetCatalog()->GetString(("Use the primary mouse-button to rotate, other buttons to set the rotation center." ), "Manipulators"); |
608 | } |
609 | |
610 | |
611 | const char* |
612 | RotationManipulator::ReturnName() |
613 | { |
614 | return B_TRANSLATE("Rotate" B_UTF8_ELLIPSIS)BLocaleRoster::Default()->GetCatalog()->GetString(("Rotate" "\xE2\x80\xA6"), "Manipulators"); |
615 | } |
616 | |
617 | |
618 | // #pragma mark -- RotationManipulatorConfigurationView |
619 | |
620 | |
621 | RotationManipulatorConfigurationView::RotationManipulatorConfigurationView( |
622 | RotationManipulator* manipulator, const BMessenger& target) |
623 | : WindowGUIManipulatorView() |
624 | , fTarget(target) |
625 | , fManipulator(manipulator) |
626 | { |
627 | fTextControl = new BTextControl("rotation", B_TRANSLATE("Angle:")BLocaleRoster::Default()->GetCatalog()->GetString(("Angle:" ), "Manipulators"), "9999.9˚", |
628 | new BMessage(HS_MANIPULATOR_ADJUSTING_FINISHED'Mafi')); |
629 | BRect bounds = fTextControl->TextView()->Bounds(); |
630 | fTextControl->TextView()->SetExplicitMaxSize(BSize(StringWidth("-999.99'"), bounds.Height())); |
631 | |
632 | SetLayout(BLayoutBuilder::Group<>(this, B_VERTICAL) |
633 | .Add(fTextControl) |
634 | ); |
635 | |
636 | RotationManipulatorSettings* settings |
637 | = (RotationManipulatorSettings*)manipulator->ReturnSettings(); |
638 | char text[256]; |
639 | sprintf(text, "%.1f˚", settings->angle); |
640 | fTextControl->TextView()->SetText(text); |
641 | |
642 | delete settings; |
643 | } |
644 | |
645 | |
646 | void |
647 | RotationManipulatorConfigurationView::AttachedToWindow() |
648 | { |
649 | fTextControl->SetTarget(this); |
650 | |
651 | if (BView* parent = Parent()) { |
652 | SetLowColor(parent->LowColor()); |
653 | SetViewColor(parent->ViewColor()); |
654 | } |
655 | |
656 | fTextControl->MakeFocus(true); |
657 | |
658 | WindowGUIManipulatorView::AttachedToWindow(); |
659 | } |
660 | |
661 | |
662 | void |
663 | RotationManipulatorConfigurationView::MessageReceived(BMessage* message) |
664 | { |
665 | switch (message->what) { |
666 | case HS_MANIPULATOR_ADJUSTING_FINISHED'Mafi': { |
667 | BTextView *text_view = fTextControl->TextView(); |
668 | char float_text[256]; |
669 | const char *text = text_view->Text(); |
670 | float angle = 0; |
671 | int decimal_place = 0; |
672 | float sign = 1; |
673 | |
674 | for (uint32 i = 0; i < strlen(text); i++) { |
675 | if (isdigit(text[i])(__ctype_b[(int)((text[i]))] & (unsigned short int)_ISdigit ) != 0) { |
676 | float new_number = text[i] - '0'; |
677 | if (decimal_place <= 0) |
678 | angle = 10*angle + new_number; |
679 | else { |
680 | angle = angle + new_number / pow(10,decimal_place); |
681 | decimal_place++; |
682 | } |
683 | } |
684 | else if (((text[i] == '.') || (text[i] == ',')) && (decimal_place <= 0)) { |
685 | decimal_place = 1; |
686 | } |
687 | else if ((decimal_place <= 0) && (angle == 0) && (text[i] == '-')) |
688 | sign = -1; |
689 | } |
690 | |
691 | angle = sign*angle; |
692 | |
693 | while (angle > 360) |
694 | angle -= 360; |
695 | if (angle > 180) |
696 | angle -= 360; |
697 | |
698 | while (angle < -360) |
699 | angle += 360; |
700 | if (angle < -180) |
701 | angle += 360; |
702 | |
703 | sprintf(float_text,"%.1f˚",angle); |
704 | text_view->SetText(float_text); |
705 | fManipulator->SetAngle(angle); |
706 | if (fTarget.IsValid()) |
707 | fTarget.SendMessage(message); |
708 | } break; |
709 | |
710 | default: { |
711 | WindowGUIManipulatorView::MessageReceived(message); |
712 | } break; |
713 | } |
714 | } |
715 | |
716 | |
717 | void |
718 | RotationManipulatorConfigurationView::SetAngle(float angle) |
719 | { |
720 | BWindow* window = Window(); |
721 | if (window && window->Lock()) { |
722 | char text[256]; |
723 | sprintf(text, "%.1f˚", angle); |
724 | fTextControl->TextView()->SetText(text); |
725 | window->Unlock(); |
726 | } |
727 | } |
728 | |
729 | |
730 | void |
731 | RotationManipulatorConfigurationView::SetTarget(const BMessenger& target) |
732 | { |
733 | fTarget = target; |
734 | } |