File: | home/HaikuArchives/ArtPaint/artpaint/paintwindow/ImageView.cpp |
Warning: | line 1673, column 3 Use of memory after it is freed |
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 "Cursors.h" | |||
12 | #include "DrawingTools.h" | |||
13 | #include "Image.h" | |||
14 | #include "ImageAdapter.h" | |||
15 | #include "ImageView.h" | |||
16 | #include "Layer.h" | |||
17 | #include "LayerWindow.h" | |||
18 | #include "Manipulator.h" | |||
19 | #include "ManipulatorServer.h" | |||
20 | #include "ManipulatorWindow.h" | |||
21 | #include "MessageConstants.h" | |||
22 | #include "PaintApplication.h" | |||
23 | #include "PaintWindow.h" | |||
24 | #include "Patterns.h" | |||
25 | #include "ProjectFileFunctions.h" | |||
26 | #include "Selection.h" | |||
27 | #include "SettingsServer.h" | |||
28 | #include "StatusBarGUIManipulator.h" | |||
29 | #include "StatusView.h" | |||
30 | #include "TextManipulator.h" | |||
31 | #include "ToolManager.h" | |||
32 | #include "Tools.h" | |||
33 | #include "UndoQueue.h" | |||
34 | #include "UtilityClasses.h" | |||
35 | #include "WindowGUIManipulator.h" | |||
36 | ||||
37 | ||||
38 | #include <Alert.h> | |||
39 | #include <Catalog.h> | |||
40 | #include <ClassInfo.h> | |||
41 | #include <Clipboard.h> | |||
42 | #include <MenuBar.h> | |||
43 | #include <MenuItem.h> | |||
44 | #include <Message.h> | |||
45 | #include <PopUpMenu.h> | |||
46 | #include <Screen.h> | |||
47 | #include <ScrollBar.h> | |||
48 | #include <Slider.h> | |||
49 | #include <StatusBar.h> | |||
50 | #include <StringFormat.h> | |||
51 | #include <Window.h> | |||
52 | ||||
53 | ||||
54 | #include <new> | |||
55 | ||||
56 | ||||
57 | #undef B_TRANSLATION_CONTEXT"ImageView" | |||
58 | #define B_TRANSLATION_CONTEXT"ImageView" "ImageView" | |||
59 | ||||
60 | ||||
61 | ImageView::ImageView(BRect frame, float width, float height) | |||
62 | : BView(frame,"image_view",B_FOLLOW_NONE0,B_WILL_DRAW) | |||
63 | { | |||
64 | // Initialize the undo-queue | |||
65 | undo_queue = new UndoQueue(NULL__null,NULL__null,this); | |||
66 | ||||
67 | // This will only be set once after reafing the prefs-file | |||
68 | // UndoQueue::SetQueueDepth(((PaintApplication*)be_app)->GlobalSettings()->undo_queue_depth); | |||
69 | ||||
70 | // Initialize the image. | |||
71 | the_image = new Image(this,width,height,undo_queue); | |||
72 | current_display_mode = FULL_RGB_DISPLAY_MODE; | |||
73 | ||||
74 | // here set the magnify_scale for image | |||
75 | magnify_scale = 1.0; | |||
76 | ||||
77 | // here we set the grid | |||
78 | setGrid(BPoint(0,0),1); | |||
79 | ||||
80 | // We are not yet inside any actions, so... | |||
81 | mouse_mutex = create_sem(1,"mouse_mutex"); | |||
82 | action_semaphore = create_sem(1,"action_semaphore"); | |||
83 | ||||
84 | // Set the correct color for view (i.e. B_TRANSPARENT_32_BIT) | |||
85 | SetViewColor(B_TRANSPARENT_32_BIT); | |||
86 | ||||
87 | fManipulator = NULL__null; | |||
88 | manipulator_window = NULL__null; | |||
89 | manipulator_finishing_message = NULL__null; | |||
90 | ||||
91 | // Create an empty selection. | |||
92 | selection = new Selection(BRect(0,0,width-1,height-1)); | |||
93 | selection->StartDrawing(this,magnify_scale); | |||
94 | ||||
95 | cursor_mode = NORMAL_CURSOR_MODE; | |||
96 | manipulated_layers = HS_MANIPULATE_NO_LAYER'Mnnl'; | |||
97 | ||||
98 | // Initialize the magnify-scale array | |||
99 | mag_scale_array_length = 15; | |||
100 | mag_scale_array = new float[mag_scale_array_length]; | |||
101 | ||||
102 | mag_scale_array[0] = 0.10; | |||
103 | mag_scale_array[1] = 0.125; | |||
104 | mag_scale_array[2] = 0.175; | |||
105 | mag_scale_array[3] = 0.25; | |||
106 | mag_scale_array[4] = 0.35; | |||
107 | mag_scale_array[5] = 0.50; | |||
108 | mag_scale_array[6] = 0.65; | |||
109 | mag_scale_array[7] = 0.80; | |||
110 | mag_scale_array[8] = 1.00; | |||
111 | mag_scale_array[9] = 1.50; | |||
112 | mag_scale_array[10] = 2.00; | |||
113 | mag_scale_array[11] = 3.00; | |||
114 | mag_scale_array[12] = 4.00; | |||
115 | mag_scale_array[13] = 8.00; | |||
116 | mag_scale_array[14] = 16.00; | |||
117 | ||||
118 | mag_scale_array_index = -1; // This has not yet been decided | |||
119 | ||||
120 | reference_point = BPoint(0,0); | |||
121 | use_reference_point = FALSE0; | |||
122 | ||||
123 | project_changed = 0; | |||
124 | image_changed = 0; | |||
125 | ||||
126 | project_name = NULL__null; | |||
127 | image_name = NULL__null; | |||
128 | ||||
129 | AddFilter(new BMessageFilter(B_KEY_DOWN, KeyFilterFunction)); | |||
130 | } | |||
131 | ||||
132 | ||||
133 | ImageView::~ImageView() | |||
134 | { | |||
135 | // Here we free all allocated memory. | |||
136 | ||||
137 | // Delete the view manipulator and close it's possible window. | |||
138 | if (manipulator_window != NULL__null) { | |||
139 | manipulator_window->Lock(); | |||
140 | manipulator_window->Close(); | |||
141 | } | |||
142 | delete fManipulator; | |||
143 | ||||
144 | // Delete the undo-queue | |||
145 | delete undo_queue; | |||
146 | ||||
147 | // Delete the selection | |||
148 | delete selection; | |||
149 | ||||
150 | // Delete the image | |||
151 | delete the_image; | |||
152 | ||||
153 | delete[] mag_scale_array; | |||
154 | ||||
155 | // Delete the semaphores | |||
156 | delete_sem(mouse_mutex); | |||
157 | delete_sem(action_semaphore); | |||
158 | } | |||
159 | ||||
160 | void ImageView::AttachedToWindow() | |||
161 | { | |||
162 | // Set the type (dithered or full color). | |||
163 | BScreen screen(Window()); | |||
164 | if (screen.ColorSpace() == B_CMAP8) | |||
165 | SetDisplayMode(DITHERED_8_BIT_DISPLAY_MODE); | |||
166 | else | |||
167 | SetDisplayMode(FULL_RGB_DISPLAY_MODE); | |||
168 | ||||
169 | // Make the composite picture (and also update miniature images). | |||
170 | the_image->Render(); | |||
171 | ||||
172 | // Initialize the undo-queue | |||
173 | undo_queue->SetMenuItems(Window()->KeyMenuBar()->FindItem(HS_UNDO'unDo'),Window()->KeyMenuBar()->FindItem(HS_REDO'reDo')); | |||
174 | ||||
175 | ||||
176 | // Make this view the focus-view (receives key-down events). | |||
177 | MakeFocus(); | |||
178 | } | |||
179 | ||||
180 | void ImageView::Draw(BRect updateRect) | |||
181 | { | |||
182 | // copy image from bitmap to the part requiring updating | |||
183 | ||||
184 | SetDrawingMode(B_OP_COPY); | |||
185 | ||||
186 | BRegion a_region; | |||
187 | GetClippingRegion(&a_region); | |||
188 | for (int32 i=0;i<a_region.CountRects();i++) { | |||
189 | BlitImage(convertViewRectToBitmap(a_region.RectAt(i) & updateRect)); | |||
190 | } | |||
191 | ||||
192 | // Draw the selection also | |||
193 | selection->Draw(); | |||
194 | ||||
195 | // Make the manipulator draw it's UI here. | |||
196 | DrawManipulatorGUI(FALSE0); | |||
197 | ||||
198 | // finally Flush() after drawing asynchronously | |||
199 | Flush(); | |||
200 | ||||
201 | } | |||
202 | ||||
203 | ||||
204 | void ImageView::BlitImage(BRect bitmap_rect) | |||
205 | { | |||
206 | BRect image_rect; | |||
207 | float mag_scale = getMagScale(); | |||
208 | ||||
209 | BBitmap *source_bitmap; | |||
210 | if ((current_display_mode == FULL_RGB_DISPLAY_MODE) || (the_image->IsDitheredUpToDate() == FALSE0)) | |||
211 | source_bitmap = the_image->ReturnRenderedImage(); | |||
212 | else | |||
213 | source_bitmap = the_image->ReturnDitheredImage(); | |||
214 | ||||
215 | if (mag_scale == 1.0) { | |||
216 | image_rect = bitmap_rect; | |||
217 | DrawBitmapAsync(source_bitmap,image_rect,bitmap_rect); | |||
218 | } | |||
219 | else if (mag_scale != 1.0) { | |||
220 | image_rect = convertBitmapRectToView(bitmap_rect); | |||
221 | DrawBitmapAsync(source_bitmap,bitmap_rect,image_rect); | |||
222 | } | |||
223 | } | |||
224 | ||||
225 | ||||
226 | void ImageView::UpdateImage(BRect bitmap_rect) | |||
227 | { | |||
228 | bitmap_rect = bitmap_rect & the_image->ReturnRenderedImage()->Bounds(); | |||
229 | the_image->Render(bitmap_rect); | |||
230 | BlitImage(bitmap_rect); | |||
231 | } | |||
232 | ||||
233 | ||||
234 | void ImageView::DrawManipulatorGUI(bool blit_image) | |||
235 | { | |||
236 | GUIManipulator *gui_manipulator = cast_as(fManipulator,GUIManipulator)(dynamic_cast<GUIManipulator*>(fManipulator)); | |||
237 | if (gui_manipulator != NULL__null) { | |||
238 | if (blit_image == TRUE1) { | |||
239 | for (int32 i=0;i<region_drawn_by_manipulator.CountRects();i++) { | |||
240 | BlitImage(convertViewRectToBitmap(region_drawn_by_manipulator.RectAt(i))); | |||
241 | } | |||
242 | } | |||
243 | ||||
244 | region_drawn_by_manipulator = gui_manipulator->Draw(this,getMagScale()); | |||
245 | } | |||
246 | else { | |||
247 | region_drawn_by_manipulator = BRegion(); | |||
248 | } | |||
249 | } | |||
250 | ||||
251 | ||||
252 | void ImageView::KeyDown(const char *bytes, int32 numBytes) | |||
253 | { | |||
254 | if (*bytes == B_LEFT_ARROW) { | |||
255 | BRect bounds = Bounds(); | |||
256 | float delta = bounds.Width() / 2; | |||
257 | if (bounds.left - delta < 0) delta = bounds.left; | |||
258 | ScrollBy(-delta, 0); | |||
259 | } | |||
260 | else if (*bytes == B_UP_ARROW) { | |||
261 | BRect bounds = Bounds(); | |||
262 | float delta = bounds.Height() / 2; | |||
263 | if (bounds.top - delta < 0) delta = bounds.top; | |||
264 | ScrollBy(0, -delta); | |||
265 | } | |||
266 | else if (*bytes == B_RIGHT_ARROW) { | |||
267 | BRect bounds = Bounds(); | |||
268 | float delta = bounds.Width() / 2; | |||
269 | BRect bitmap_rect = convertBitmapRectToView(the_image->ReturnRenderedImage()->Bounds()); | |||
270 | if (bounds.right + delta > bitmap_rect.right) delta = bitmap_rect.right - bounds.right; | |||
271 | ScrollBy(delta, 0); | |||
272 | } | |||
273 | else if (*bytes == B_DOWN_ARROW) { | |||
274 | BRect bounds = Bounds(); | |||
275 | float delta = bounds.Height() / 2; | |||
276 | BRect bitmap_rect = convertBitmapRectToView(the_image->ReturnRenderedImage()->Bounds()); | |||
277 | if (bounds.bottom + delta > bitmap_rect.bottom) delta = bitmap_rect.bottom - bounds.bottom; | |||
278 | ScrollBy(0, delta); | |||
279 | } | |||
280 | else if (fManipulator == NULL__null) { | |||
281 | ToolManager::Instance().KeyDown(this,bytes,numBytes); | |||
282 | } | |||
283 | } | |||
284 | ||||
285 | void ImageView::MessageReceived(BMessage *message) | |||
286 | { | |||
287 | BMessage message_to_window; | |||
288 | BMessage message_to_app; | |||
289 | ||||
290 | // here check what the message is all about and initiate proper action | |||
291 | switch (message->what) { | |||
292 | // This comes from layer's view and tells us to change the active layer. | |||
293 | case HS_LAYER_ACTIVATED'LaAc': | |||
294 | // Only change the layer if we can acquire the action_semaphore. | |||
295 | if (acquire_sem_etc(action_semaphore,1,B_TIMEOUT,0) == B_OK((int)0)) { | |||
296 | int32 activated_layer_id; | |||
297 | Layer *activated_layer; | |||
298 | message->FindInt32("layer_id",&activated_layer_id); | |||
299 | message->FindPointer("layer_pointer",(void**)&activated_layer); | |||
300 | if (the_image->ChangeActiveLayer(activated_layer,activated_layer_id) == TRUE1) | |||
301 | ActiveLayerChanged(); | |||
302 | ||||
303 | release_sem(action_semaphore); | |||
304 | } | |||
305 | break; | |||
306 | ||||
307 | case HS_ZOOM_IMAGE_IN'ZImI': { | |||
308 | if (mag_scale_array_index == -1) { | |||
309 | // Search for the right index. | |||
310 | mag_scale_array_index = 0; | |||
311 | while ((mag_scale_array_index < mag_scale_array_length - 1) | |||
312 | && (mag_scale_array[mag_scale_array_index] <= magnify_scale)) { | |||
313 | mag_scale_array_index++; | |||
314 | } | |||
315 | } else { | |||
316 | mag_scale_array_index = min_c(mag_scale_array_index + 1,((mag_scale_array_index + 1)>(mag_scale_array_length - 1)? (mag_scale_array_length - 1):(mag_scale_array_index + 1)) | |||
317 | mag_scale_array_length - 1)((mag_scale_array_index + 1)>(mag_scale_array_length - 1)? (mag_scale_array_length - 1):(mag_scale_array_index + 1)); | |||
318 | } | |||
319 | ||||
320 | setMagScale(mag_scale_array[mag_scale_array_index]); | |||
321 | } break; | |||
322 | ||||
323 | case HS_ZOOM_IMAGE_OUT'ZImO': { | |||
324 | if (mag_scale_array_index == -1) { | |||
325 | // Search for the right index. | |||
326 | mag_scale_array_index = mag_scale_array_length - 1; | |||
327 | while ((mag_scale_array_index > 0) | |||
328 | && (mag_scale_array[mag_scale_array_index] >= magnify_scale)) { | |||
329 | mag_scale_array_index--; | |||
330 | } | |||
331 | } else { | |||
332 | mag_scale_array_index = max_c(mag_scale_array_index - 1, 0)((mag_scale_array_index - 1)>(0)?(mag_scale_array_index - 1 ):(0)); | |||
333 | } | |||
334 | ||||
335 | setMagScale(mag_scale_array[mag_scale_array_index]); | |||
336 | } break; | |||
337 | ||||
338 | case HS_SET_MAGNIFYING_SCALE'SmgS': { | |||
339 | mag_scale_array_index = -1; | |||
340 | float newMagScale; | |||
341 | if (message->FindFloat("magnifying_scale", &newMagScale) == B_OK((int)0)) { | |||
342 | setMagScale(newMagScale); | |||
343 | ((PaintWindow*)Window())->displayMag(newMagScale); | |||
344 | } else { | |||
345 | void *source; | |||
346 | if (message->FindPointer("source", &source) == B_OK((int)0)) { | |||
347 | BSlider *slider = static_cast<BSlider*> (source); | |||
348 | if (slider == NULL__null) | |||
349 | break; | |||
350 | ||||
351 | // Convert nonlinear from [10,1600] -> [0.1,16] | |||
352 | float scale = (pow(10.0, (slider->Value() - 10.0) / 1590.0) | |||
353 | - 1.0) * (15.9 / 9.0) + 0.1; | |||
354 | setMagScale(scale); | |||
355 | } | |||
356 | } | |||
357 | } break; | |||
358 | ||||
359 | case HS_GRID_ADJUSTED'Grdj': { | |||
360 | BPoint origin; | |||
361 | if (message->FindPoint("origin",&origin) == B_OK((int)0)) { | |||
362 | int32 unit; | |||
363 | if (message->FindInt32("unit",&unit) == B_OK((int)0)) { | |||
364 | grid_unit = unit; | |||
365 | grid_origin = origin; | |||
366 | } | |||
367 | } | |||
368 | } break; | |||
369 | ||||
370 | // This comes from layer's view and tells us to change the visibility for that layer. | |||
371 | case HS_LAYER_VISIBILITY_CHANGED'LviC': | |||
372 | int32 changed_layer_id; | |||
373 | Layer *changed_layer; | |||
374 | message->FindInt32("layer_id",&changed_layer_id); | |||
375 | message->FindPointer("layer_pointer",(void**)&changed_layer); | |||
376 | if (the_image->ToggleLayerVisibility(changed_layer,changed_layer_id) == TRUE1) { | |||
377 | Invalidate(); | |||
378 | AddChange(); // Is this really necessary? | |||
379 | } | |||
380 | break; | |||
381 | ||||
382 | // This comes from layer's view and tells us to move layer to another position in the list. | |||
383 | case HS_LAYER_POSITION_CHANGED'LpoC': | |||
384 | int32 positions_moved; | |||
385 | message->FindInt32("layer_id",&changed_layer_id); | |||
386 | message->FindPointer("layer_pointer",(void**)&changed_layer); | |||
387 | message->FindInt32("positions_moved",&positions_moved); | |||
388 | if (the_image->ChangeLayerPosition(changed_layer,changed_layer_id,positions_moved) == TRUE1) { | |||
389 | Invalidate(); | |||
390 | AddChange(); | |||
391 | } | |||
392 | break; | |||
393 | ||||
394 | // This comes from layer's view and tells us to delete the layer. | |||
395 | case HS_DELETE_LAYER'DelL': | |||
396 | if (!PostponeMessageAndFinishManipulator()) { | |||
397 | Layer *removed_layer; | |||
398 | int32 removed_layer_id; | |||
399 | message->FindInt32("layer_id",&removed_layer_id); | |||
400 | message->FindPointer("layer_pointer",(void**)&removed_layer); | |||
401 | if (the_image->RemoveLayer(removed_layer,removed_layer_id) == TRUE1) { | |||
402 | ActiveLayerChanged(); | |||
403 | AddChange(); | |||
404 | } | |||
405 | LayerWindow::ActiveWindowChanged(Window(),the_image->LayerList(),the_image->ReturnThumbnailImage()); | |||
406 | Invalidate(); | |||
407 | } | |||
408 | break; | |||
409 | ||||
410 | // This comes from layer's view and tells us to merge that layer with the one | |||
411 | // that is on top of it. If no layer is on top of it nothing should be done. | |||
412 | // The merged layer will then be made visible if necessary. But the active layer | |||
413 | // stays the same unless one of the merged layers was the active layer | |||
414 | case HS_MERGE_WITH_UPPER_LAYER'MrWu': | |||
415 | if (!PostponeMessageAndFinishManipulator()) { | |||
416 | Layer *merged_layer; | |||
417 | int32 merged_layer_id; | |||
418 | message->FindInt32("layer_id",&merged_layer_id); | |||
419 | message->FindPointer("layer_pointer",(void**)&merged_layer); | |||
420 | if (the_image->MergeLayers(merged_layer,merged_layer_id,TRUE1) == TRUE1) { | |||
421 | LayerWindow::ActiveWindowChanged(Window(),the_image->LayerList(),the_image->ReturnThumbnailImage()); | |||
422 | Invalidate(); | |||
423 | AddChange(); | |||
424 | } | |||
425 | } | |||
426 | break; | |||
427 | ||||
428 | // This comes from layer's view and tells us to merge that layer with the one | |||
429 | // that is under it. If no layer is under it nothing should be done. | |||
430 | // The merged layer will then be made visible if necessary. But the active layer | |||
431 | // stays the same unless one of the merged layers was the active layer | |||
432 | case HS_MERGE_WITH_LOWER_LAYER'MrWl': | |||
433 | if (!PostponeMessageAndFinishManipulator()) { | |||
434 | Layer *merged_layer; | |||
435 | int32 merged_layer_id; | |||
436 | message->FindInt32("layer_id",&merged_layer_id); | |||
437 | message->FindPointer("layer_pointer",(void**)&merged_layer); | |||
438 | if (the_image->MergeLayers(merged_layer,merged_layer_id,FALSE0) == TRUE1) { | |||
439 | LayerWindow::ActiveWindowChanged(Window(),the_image->LayerList(),the_image->ReturnThumbnailImage()); | |||
440 | Invalidate(); | |||
441 | AddChange(); | |||
442 | } | |||
443 | } | |||
444 | break; | |||
445 | ||||
446 | case HS_ADD_LAYER_FRONT'AdLf': | |||
447 | case HS_ADD_LAYER_BEHIND'AdLb': | |||
448 | { | |||
449 | Layer *other_layer; | |||
450 | message->FindPointer("layer_pointer",(void**)&other_layer); | |||
451 | try { | |||
452 | the_image->AddLayer(NULL__null,other_layer,message->what == HS_ADD_LAYER_FRONT'AdLf'); | |||
453 | LayerWindow::ActiveWindowChanged(Window(),the_image->LayerList(),the_image->ReturnThumbnailImage()); | |||
454 | ActiveLayerChanged(); | |||
455 | Invalidate(); | |||
456 | AddChange(); | |||
457 | } | |||
458 | catch (std::bad_alloc){ | |||
459 | ShowAlert(CANNOT_ADD_LAYER_ALERT); | |||
460 | } | |||
461 | break; | |||
462 | } | |||
463 | ||||
464 | ||||
465 | case HS_DUPLICATE_LAYER'DupL': | |||
466 | { | |||
467 | Layer *duplicated_layer; | |||
468 | int32 duplicated_layer_id; | |||
469 | message->FindInt32("layer_id",&duplicated_layer_id); | |||
470 | message->FindPointer("layer_pointer",(void**)&duplicated_layer); | |||
471 | try { | |||
472 | if (the_image->DuplicateLayer(duplicated_layer,duplicated_layer_id) == TRUE1) { | |||
473 | LayerWindow::ActiveWindowChanged(Window(),the_image->LayerList(),the_image->ReturnThumbnailImage()); | |||
474 | ActiveLayerChanged(); | |||
475 | Invalidate(); | |||
476 | AddChange(); | |||
477 | } | |||
478 | } | |||
479 | catch (std::bad_alloc e) { | |||
480 | ShowAlert(CANNOT_ADD_LAYER_ALERT); | |||
481 | } | |||
482 | break; | |||
483 | } | |||
484 | // This comes when a layer's miniature image is dragged on the view. | |||
485 | // We should copy the image from that layer and add it to this image. | |||
486 | case HS_LAYER_DRAGGED'Drla': | |||
487 | if (message->WasDropped()) { | |||
488 | BBitmap *to_be_copied; | |||
489 | if (message->FindPointer("layer_bitmap",(void**)&to_be_copied) == B_OK((int)0)) { | |||
490 | try { | |||
491 | BBitmap *new_bitmap = new BBitmap(to_be_copied); | |||
492 | if (the_image->AddLayer(new_bitmap,NULL__null,TRUE1) != NULL__null) { | |||
493 | Invalidate(); | |||
494 | LayerWindow::ActiveWindowChanged(Window(),the_image->LayerList(),the_image->ReturnThumbnailImage()); | |||
495 | AddChange(); | |||
496 | } | |||
497 | } | |||
498 | catch (std::bad_alloc) { | |||
499 | ShowAlert(CANNOT_ADD_LAYER_ALERT); | |||
500 | } | |||
501 | } | |||
502 | } | |||
503 | break; | |||
504 | ||||
505 | // this comes from menubar->"Edit"->"Invert Selection", we should then invert the | |||
506 | // selected area and redisplay it | |||
507 | case HS_INVERT_SELECTION'InSl': | |||
508 | if (!fManipulator) { | |||
509 | selection->Invert(); | |||
510 | if (!(*undo_queue->ReturnSelectionData() == *selection->ReturnSelectionData())) { | |||
511 | UndoEvent *new_event = undo_queue->AddUndoEvent(B_TRANSLATE("Invert selection")BLocaleRoster::Default()->GetCatalog()->GetString(("Invert selection" ), "ImageView"),the_image->ReturnThumbnailImage()); | |||
512 | if (new_event != NULL__null) { | |||
513 | new_event->SetSelectionData(undo_queue->ReturnSelectionData()); | |||
514 | undo_queue->SetSelectionData(selection->ReturnSelectionData()); | |||
515 | } | |||
516 | } | |||
517 | ||||
518 | Invalidate(); | |||
519 | } | |||
520 | break; | |||
521 | ||||
522 | // this comes from menubar->"Edit"->"Clear Selection", we should then clear the | |||
523 | // selection and redisplay the image | |||
524 | case HS_CLEAR_SELECTION'ClSl': | |||
525 | if (!fManipulator) { | |||
526 | selection->Clear(); | |||
527 | if (!(*undo_queue->ReturnSelectionData() == *selection->ReturnSelectionData())) { | |||
528 | UndoEvent *new_event = undo_queue->AddUndoEvent(B_TRANSLATE("Clear selection")BLocaleRoster::Default()->GetCatalog()->GetString(("Clear selection" ), "ImageView"),the_image->ReturnThumbnailImage()); | |||
529 | if (new_event != NULL__null) { | |||
530 | new_event->SetSelectionData(undo_queue->ReturnSelectionData()); | |||
531 | undo_queue->SetSelectionData(selection->ReturnSelectionData()); | |||
532 | } | |||
533 | } | |||
534 | Invalidate(); | |||
535 | } | |||
536 | break; | |||
537 | ||||
538 | case HS_GROW_SELECTION'GrSl': | |||
539 | if (!fManipulator) { | |||
540 | selection->Dilatate(); | |||
541 | if (!(*undo_queue->ReturnSelectionData() == *selection->ReturnSelectionData())) { | |||
542 | UndoEvent *new_event = undo_queue->AddUndoEvent(B_TRANSLATE("Grow selection")BLocaleRoster::Default()->GetCatalog()->GetString(("Grow selection" ), "ImageView"),the_image->ReturnThumbnailImage()); | |||
543 | if (new_event != NULL__null) { | |||
544 | new_event->SetSelectionData(undo_queue->ReturnSelectionData()); | |||
545 | undo_queue->SetSelectionData(selection->ReturnSelectionData()); | |||
546 | } | |||
547 | } | |||
548 | Invalidate(); | |||
549 | } | |||
550 | break; | |||
551 | ||||
552 | case HS_SHRINK_SELECTION'SrSL': | |||
553 | if (!fManipulator) { | |||
554 | selection->Erode(); | |||
555 | if (!(*undo_queue->ReturnSelectionData() == *selection->ReturnSelectionData())) { | |||
556 | UndoEvent *new_event = undo_queue->AddUndoEvent(B_TRANSLATE("Shrink selection")BLocaleRoster::Default()->GetCatalog()->GetString(("Shrink selection" ), "ImageView"),the_image->ReturnThumbnailImage()); | |||
557 | if (new_event != NULL__null) { | |||
558 | new_event->SetSelectionData(undo_queue->ReturnSelectionData()); | |||
559 | undo_queue->SetSelectionData(selection->ReturnSelectionData()); | |||
560 | } | |||
561 | } | |||
562 | Invalidate(); | |||
563 | } | |||
564 | break; | |||
565 | ||||
566 | // this comes from menubar->"Canvas"->"Clear Canvas", we should then clear all the | |||
567 | // layers and recalculate the composite picture and redisplay | |||
568 | case HS_CLEAR_CANVAS'Clcv': | |||
569 | if (acquire_sem_etc(action_semaphore,1,B_TIMEOUT,0) == B_OK((int)0)) { | |||
570 | rgb_color c = ((PaintApplication*)be_app)->Color(FALSE0); | |||
571 | if (the_image->ClearLayers(c) == TRUE1) { | |||
572 | Invalidate(); | |||
573 | AddChange(); | |||
574 | } | |||
575 | release_sem(action_semaphore); | |||
576 | } | |||
577 | break; | |||
578 | ||||
579 | // This comes from menubar->"Layer"->"Clear Layer". We should clear the layer, recalculate | |||
580 | // the composite picture and redisplay the image. | |||
581 | case HS_CLEAR_LAYER'Clla': | |||
582 | if (acquire_sem_etc(action_semaphore,1,B_TIMEOUT,0) == B_OK((int)0)) { | |||
583 | rgb_color c = ((PaintApplication*)be_app)->Color(FALSE0); | |||
584 | if (the_image->ClearCurrentLayer(c) == TRUE1) { | |||
585 | Invalidate(); | |||
586 | AddChange(); | |||
587 | } | |||
588 | release_sem(action_semaphore); | |||
589 | } | |||
590 | break; | |||
591 | ||||
592 | case B_COPY: | |||
593 | case B_CUT: | |||
594 | { | |||
595 | if (!fManipulator) { | |||
596 | int32 copied_layers; | |||
597 | if (message->FindInt32("layers",&copied_layers) == B_OK((int)0)) { | |||
598 | DoCopyOrCut(copied_layers,message->what == B_CUT); | |||
599 | } | |||
600 | } | |||
601 | break; | |||
602 | } | |||
603 | ||||
604 | case B_PASTE: | |||
605 | if (!fManipulator) | |||
606 | DoPaste(); | |||
607 | break; | |||
608 | ||||
609 | case HS_UNDO'unDo': | |||
610 | if (!fManipulator) | |||
611 | Undo(); | |||
612 | else | |||
613 | PostponeMessageAndFinishManipulator(); | |||
614 | ||||
615 | break; | |||
616 | ||||
617 | case HS_REDO'reDo': | |||
618 | if (!fManipulator) | |||
619 | Redo(); | |||
620 | else | |||
621 | PostponeMessageAndFinishManipulator(); | |||
622 | ||||
623 | break; | |||
624 | ||||
625 | case HS_START_MANIPULATOR'Stmi': { | |||
626 | if (PostponeMessageAndFinishManipulator()) | |||
627 | break; | |||
628 | ||||
629 | if (message->FindInt32("manipulator_type", &manip_type) != B_OK((int)0)) | |||
630 | break; | |||
631 | ||||
632 | message->FindInt32("image_id", &add_on_id); | |||
633 | try { | |||
634 | ManipulatorServer* server = ManipulatorServer::Instance(); | |||
635 | if (!server) | |||
636 | throw std::bad_alloc(); | |||
637 | ||||
638 | fManipulator = server->ManipulatorFor((manipulator_type)manip_type, | |||
639 | add_on_id); | |||
640 | status_t err = message->FindInt32("layers",&manipulated_layers); | |||
641 | if ((err == B_OK((int)0)) && (fManipulator != NULL__null)) { | |||
642 | GUIManipulator *gui_manipulator = cast_as(fManipulator,GUIManipulator)(dynamic_cast<GUIManipulator*>(fManipulator)); | |||
643 | ImageAdapter *adapter = cast_as(fManipulator,ImageAdapter)(dynamic_cast<ImageAdapter*>(fManipulator)); | |||
644 | if (adapter != NULL__null) | |||
645 | adapter->SetImage(the_image); | |||
646 | ||||
647 | SetCursor(); | |||
648 | // If the manipulator is not a GUIManipulator we put it to finish its | |||
649 | // business. If the manipulator is actually a GUIManipulator we give the | |||
650 | // correct preview-bitmap to the manipulator and set up its GUI. | |||
651 | if (gui_manipulator == NULL__null) { | |||
652 | start_thread(MANIPULATOR_FINISHER_THREAD); | |||
653 | } else { | |||
654 | // The order is important, first set the preview-bitmap | |||
655 | // and only after that open the GUI for the manipulator. | |||
656 | if (manipulated_layers == HS_MANIPULATE_CURRENT_LAYER'Mncl') { | |||
657 | gui_manipulator->SetPreviewBitmap(the_image->ReturnActiveBitmap()); | |||
658 | } | |||
659 | else { | |||
660 | gui_manipulator->SetPreviewBitmap(the_image->ReturnRenderedImage()); | |||
661 | } | |||
662 | //StatusBarGUIManipulator *status_bar_gui_manipulator = cast_as(gui_manipulator,StatusBarGUIManipulator); | |||
663 | WindowGUIManipulator *window_gui_manipulator = cast_as(gui_manipulator,WindowGUIManipulator)(dynamic_cast<WindowGUIManipulator*>(gui_manipulator)); | |||
664 | ||||
665 | ((PaintWindow*)Window())->SetHelpString(gui_manipulator->ReturnHelpString(),HS_TOOL_HELP_MESSAGE'TolM'); | |||
666 | if (window_gui_manipulator != NULL__null) { | |||
667 | char window_name[256]; | |||
668 | sprintf(window_name, "%s: %s", | |||
669 | ReturnProjectName(), | |||
670 | window_gui_manipulator->ReturnName()); | |||
671 | ||||
672 | BRect frame(100, 100, 200, 200); | |||
673 | if (SettingsServer* server = SettingsServer::Instance()) { | |||
674 | BMessage settings; | |||
675 | server->GetApplicationSettings(&settings); | |||
676 | settings.FindRect(skAddOnWindowFrame, &frame); | |||
677 | } | |||
678 | ||||
679 | frame = FitRectToScreen(frame); | |||
680 | manipulator_window = new ManipulatorWindow(frame, | |||
681 | window_gui_manipulator->MakeConfigurationView(this), | |||
682 | window_name, Window(), this); | |||
683 | } | |||
684 | ||||
685 | cursor_mode = MANIPULATOR_CURSOR_MODE; | |||
686 | SetCursor(); | |||
687 | ||||
688 | // The manipulator might have updated the bitmap and | |||
689 | // might also want to draw some GUI. We send a | |||
690 | // HS_MANIPULATOR_ADJUSTING_FINISHED to this view | |||
691 | // to get the manipulator update the correct bitmap. | |||
692 | if (BWindow* window = Window()) | |||
693 | window->PostMessage(HS_MANIPULATOR_ADJUSTING_FINISHED'Mafi', this); | |||
694 | } | |||
695 | } | |||
696 | } | |||
697 | catch (std::bad_alloc) { | |||
698 | ShowAlert(CANNOT_START_MANIPULATOR_ALERT); | |||
699 | delete fManipulator; | |||
700 | fManipulator = NULL__null; | |||
701 | } | |||
702 | } break; | |||
703 | ||||
704 | case HS_MANIPULATOR_FINISHED'MnFi': { | |||
705 | // First find whether the manipulator finished cancelling or OKing. | |||
706 | bool finish_status = false; | |||
707 | message->FindBool("status", &finish_status); | |||
708 | if (GUIManipulator* guiManipulator = | |||
709 | dynamic_cast<GUIManipulator*> (fManipulator)) { | |||
710 | if (WindowGUIManipulator* windowGuiManipulator = | |||
711 | dynamic_cast<WindowGUIManipulator*> (guiManipulator)) { | |||
712 | (void)windowGuiManipulator; // suppress warning | |||
713 | if (manipulator_window) { | |||
714 | manipulator_window->Lock(); | |||
715 | manipulator_window->Quit(); | |||
716 | manipulator_window = NULL__null; | |||
717 | } | |||
718 | } | |||
719 | ||||
720 | if (finish_status) { | |||
721 | start_thread(MANIPULATOR_FINISHER_THREAD); | |||
722 | AddChange(); | |||
723 | } else { | |||
724 | // The manipulator should be instructed to restore | |||
725 | // whatever changes it has made and should be quit then. | |||
726 | guiManipulator->Reset(selection); | |||
727 | ((PaintWindow*)Window())->ReturnStatusView()->DisplayToolsAndColors(); | |||
728 | delete fManipulator; | |||
729 | fManipulator = NULL__null; | |||
730 | the_image->Render(); | |||
731 | manipulated_layers = HS_MANIPULATE_NO_LAYER'Mnnl'; | |||
732 | Invalidate(); | |||
733 | } | |||
734 | } | |||
735 | cursor_mode = NORMAL_CURSOR_MODE; | |||
736 | SetCursor(); | |||
737 | // changes the help-string | |||
738 | ToolManager::Instance().NotifyViewEvent(this, TOOL_ACTIVATED); | |||
739 | } break; | |||
740 | ||||
741 | case HS_MANIPULATOR_ADJUSTING_STARTED'Mast': { | |||
742 | case HS_MANIPULATOR_ADJUSTING_FINISHED'Mafi': | |||
743 | continue_manipulator_updating = false; | |||
744 | if (message->what == HS_MANIPULATOR_ADJUSTING_STARTED'Mast') | |||
745 | continue_manipulator_updating = true; | |||
746 | start_thread(MANIPULATOR_UPDATER_THREAD); | |||
747 | } break; | |||
748 | ||||
749 | default: { | |||
750 | BView::MessageReceived(message); | |||
751 | } break; | |||
752 | } | |||
753 | } | |||
754 | ||||
755 | void ImageView::MouseDown(BPoint view_point) | |||
756 | { | |||
757 | // From this function we call view-manipulator's MouseDown-function. | |||
758 | // It will be the correct function depending on what manipulator is | |||
759 | // in use currently. | |||
760 | ||||
761 | // here read the modifier keys | |||
762 | BMessage *message = Window()->CurrentMessage(); | |||
763 | //int32 modifiers = message->FindInt32("modifiers"); | |||
764 | ||||
765 | // here we read which mousebutton was pressed | |||
766 | uint32 buttons = message->FindInt32("buttons"); | |||
767 | ||||
768 | // The window activation should probably be made a user preference. | |||
769 | // Also backgroundview should activate the window if the user wants it. | |||
770 | // // activate the window if necessary | |||
771 | if (Window()->IsActive() == FALSE0) | |||
772 | Window()->Activate(TRUE1); | |||
773 | ||||
774 | // If the view is not focus view, make it the focus view | |||
775 | if (!IsFocus()) | |||
776 | MakeFocus(true); | |||
777 | ||||
778 | // try to acquire the mouse_mutex | |||
779 | if (acquire_sem_etc(mouse_mutex,1,B_TIMEOUT,0) == B_OK((int)0)) { | |||
780 | GUIManipulator *gui_manipulator = cast_as(fManipulator,GUIManipulator)(dynamic_cast<GUIManipulator*>(fManipulator)); | |||
781 | if (gui_manipulator != NULL__null) { | |||
782 | start_thread(MANIPULATOR_MOUSE_THREAD); | |||
783 | } | |||
784 | else if (fManipulator == NULL__null){ | |||
785 | if (buttons & B_SECONDARY_MOUSE_BUTTON) { | |||
786 | BMenuItem *item = ToolManager::Instance().ToolPopUpMenu()->Go(ConvertToScreen(view_point)); | |||
787 | if (item != NULL__null) { | |||
788 | ToolManager::Instance().ChangeTool(item->Command()); | |||
789 | SetCursor(); // If the tool changes, the cursor should change too. | |||
790 | } | |||
791 | release_sem(mouse_mutex); | |||
792 | } | |||
793 | else if (buttons & B_TERTIARY_MOUSE_BUTTON) { | |||
794 | BPoint point,prev_point; | |||
795 | uint32 buttons; | |||
796 | GetMouse(&point,&buttons); | |||
797 | while (buttons) { | |||
798 | prev_point = point; | |||
799 | GetMouse(&point,&buttons); | |||
800 | ScrollBy(point.x-prev_point.x,point.y-prev_point.y); | |||
801 | snooze(25 * 1000); | |||
802 | } | |||
803 | release_sem(mouse_mutex); | |||
804 | } | |||
805 | else { | |||
806 | start_thread(PAINTER_THREAD); | |||
807 | } | |||
808 | } | |||
809 | else { | |||
810 | release_sem(mouse_mutex); | |||
811 | } | |||
812 | } | |||
813 | else { | |||
814 | if (fManipulator == NULL__null) { | |||
815 | BPoint bitmap_point; | |||
816 | uint32 buttons; | |||
817 | getCoords(&bitmap_point,&buttons,&view_point); | |||
818 | int32 clicks; | |||
819 | if (Window()->CurrentMessage()->FindInt32("clicks",&clicks) == B_OK((int)0)) | |||
820 | ToolManager::Instance().MouseDown(this,view_point,bitmap_point,buttons,clicks); | |||
821 | } | |||
822 | } | |||
823 | } | |||
824 | ||||
825 | void ImageView::MouseMoved(BPoint where, uint32 transit, const BMessage *message) | |||
826 | { | |||
827 | // here we will display the coordinates | |||
828 | // we will also change the cursor whenever mouse enters the view or leaves it | |||
829 | ||||
830 | // If we have a message being dragged over us, do not change the cursor | |||
831 | if (message == NULL__null) { | |||
832 | if ((transit == B_ENTERED_VIEW) || (transit == B_EXITED_VIEW)) { | |||
833 | if (fManipulator == NULL__null) { | |||
834 | if (transit == B_ENTERED_VIEW) | |||
835 | ToolManager::Instance().NotifyViewEvent(this,CURSOR_ENTERED_VIEW); | |||
836 | else | |||
837 | ToolManager::Instance().NotifyViewEvent(this,CURSOR_EXITED_VIEW); | |||
838 | } | |||
839 | SetCursor(); | |||
840 | } | |||
841 | } | |||
842 | else { | |||
843 | if (message->what == HS_LAYER_DRAGGED'Drla') { | |||
844 | BMessage help_view_message; | |||
845 | ||||
846 | if (transit == B_ENTERED_VIEW) { | |||
847 | help_view_message.what = HS_TEMPORARY_HELP_MESSAGE'ThlM'; | |||
848 | help_view_message.AddString("message", | |||
849 | B_TRANSLATE("Drop layer to copy it to this image.")BLocaleRoster::Default()->GetCatalog()->GetString(("Drop layer to copy it to this image." ), "ImageView")); | |||
850 | Window()->PostMessage(&help_view_message,Window()); | |||
851 | } | |||
852 | else if (transit == B_EXITED_VIEW) { | |||
853 | help_view_message.what = HS_TOOL_HELP_MESSAGE'TolM'; | |||
854 | Window()->PostMessage(&help_view_message,Window()); | |||
855 | } | |||
856 | } | |||
857 | } | |||
858 | if (transit != B_EXITED_VIEW) { | |||
859 | // change the point according to magnifying scale | |||
860 | where.x = floor(where.x / getMagScale()); | |||
861 | where.y = floor(where.y / getMagScale()); | |||
862 | ||||
863 | // round the point to grid units | |||
864 | where = roundToGrid(where); | |||
865 | ||||
866 | // Here we set the window to display coordinates. | |||
867 | ((PaintWindow *)Window())->DisplayCoordinates(where,reference_point,use_reference_point); | |||
868 | } | |||
869 | else { | |||
870 | where.x = the_image->Width(); | |||
871 | where.y = the_image->Height(); | |||
872 | ||||
873 | ((PaintWindow *)Window())->DisplayCoordinates(where,BPoint(0,0),false); | |||
874 | } | |||
875 | } | |||
876 | ||||
877 | ||||
878 | bool | |||
879 | ImageView::Quit() | |||
880 | { | |||
881 | int32 mode = B_CONTROL_ON; | |||
882 | if (SettingsServer* server = SettingsServer::Instance()) { | |||
883 | BMessage settings; | |||
884 | server->GetApplicationSettings(&settings); | |||
885 | settings.FindInt32(skQuitConfirmMode, &mode); | |||
886 | } | |||
887 | ||||
888 | if (mode == B_CONTROL_ON) { | |||
889 | if (project_changed > 0) { | |||
890 | BString text; | |||
891 | static BStringFormat format(B_TRANSLATE("{0, plural,"BLocaleRoster::Default()->GetCatalog()->GetString(("{0, plural," "one{%project_name%: You have made a change since the last time " "the project was saved.\nDo you want to save the change?}" "other{%project_name%: You have made # changes since the last time " "the project was saved.\nDo you want to save the changes?}}" ), "ImageView") | |||
892 | "one{%project_name%: You have made a change since the last time "BLocaleRoster::Default()->GetCatalog()->GetString(("{0, plural," "one{%project_name%: You have made a change since the last time " "the project was saved.\nDo you want to save the change?}" "other{%project_name%: You have made # changes since the last time " "the project was saved.\nDo you want to save the changes?}}" ), "ImageView") | |||
893 | "the project was saved.\nDo you want to save the change?}"BLocaleRoster::Default()->GetCatalog()->GetString(("{0, plural," "one{%project_name%: You have made a change since the last time " "the project was saved.\nDo you want to save the change?}" "other{%project_name%: You have made # changes since the last time " "the project was saved.\nDo you want to save the changes?}}" ), "ImageView") | |||
894 | "other{%project_name%: You have made # changes since the last time "BLocaleRoster::Default()->GetCatalog()->GetString(("{0, plural," "one{%project_name%: You have made a change since the last time " "the project was saved.\nDo you want to save the change?}" "other{%project_name%: You have made # changes since the last time " "the project was saved.\nDo you want to save the changes?}}" ), "ImageView") | |||
895 | "the project was saved.\nDo you want to save the changes?}}")BLocaleRoster::Default()->GetCatalog()->GetString(("{0, plural," "one{%project_name%: You have made a change since the last time " "the project was saved.\nDo you want to save the change?}" "other{%project_name%: You have made # changes since the last time " "the project was saved.\nDo you want to save the changes?}}" ), "ImageView")); | |||
896 | format.Format(text, project_changed); | |||
897 | text.ReplaceFirst("%project_name%", project_name); | |||
898 | ||||
899 | BAlert* alert = new BAlert(B_TRANSLATE("Unsaved changes!")BLocaleRoster::Default()->GetCatalog()->GetString(("Unsaved changes!" ), "ImageView"), text, | |||
900 | B_TRANSLATE("Cancel")BLocaleRoster::Default()->GetCatalog()->GetString(("Cancel" ), "ImageView"), | |||
901 | B_TRANSLATE("Don't save")BLocaleRoster::Default()->GetCatalog()->GetString(("Don't save" ), "ImageView"), | |||
902 | B_TRANSLATE("Save")BLocaleRoster::Default()->GetCatalog()->GetString(("Save" ), "ImageView"), B_WIDTH_AS_USUAL, | |||
903 | B_OFFSET_SPACING); | |||
904 | ||||
905 | int32 value = alert->Go(); | |||
906 | if (value == 0) // Cancel | |||
907 | return false; | |||
908 | ||||
909 | if (value == 1) // Don't save | |||
910 | return true; | |||
911 | ||||
912 | if (value == 2) { // Save | |||
913 | BMessage* message = new BMessage(HS_SAVE_PROJECT'Sapr'); | |||
914 | message->SetInt32("TryAgain", 1); | |||
915 | message->SetInt32("quitAll", ((PaintApplication*)be_app)->ShuttingDown()); | |||
916 | Window()->PostMessage(message, Window()); | |||
917 | return false; | |||
918 | } | |||
919 | ||||
920 | return true; | |||
921 | } | |||
922 | } | |||
923 | ||||
924 | if (acquire_sem_etc(action_semaphore, 1, B_TIMEOUT, 0) != B_OK((int)0)) | |||
925 | return false; | |||
926 | ||||
927 | return true; | |||
928 | } | |||
929 | ||||
930 | ||||
931 | status_t ImageView::Freeze() | |||
932 | { | |||
933 | if (acquire_sem(mouse_mutex) == B_OK((int)0)) { | |||
934 | if (acquire_sem(action_semaphore) == B_OK((int)0)) | |||
935 | return B_OK((int)0); | |||
936 | release_sem(mouse_mutex); | |||
937 | } | |||
938 | ||||
939 | // This must restore whatever the manipulator had previewed. Here we | |||
940 | // also acquire mouse_mutex and action_semaphore semaphores to protect | |||
941 | // the image from any further changes. These restorations must of course | |||
942 | // be done only after we have acquired the desired semaphores. | |||
943 | GUIManipulator *gui_manipulator = cast_as(fManipulator,GUIManipulator)(dynamic_cast<GUIManipulator*>(fManipulator)); | |||
944 | if (gui_manipulator != NULL__null) { | |||
945 | gui_manipulator->Reset(selection); | |||
946 | the_image->Render(); | |||
947 | } | |||
948 | return B_ERROR(-1); | |||
949 | } | |||
950 | ||||
951 | ||||
952 | status_t ImageView::UnFreeze() | |||
953 | { | |||
954 | // Release the semaphores. We could also tell the manipulator to preview | |||
955 | // with the settings that it last had, but we will not do it yet. | |||
956 | release_sem(mouse_mutex); | |||
957 | release_sem(action_semaphore); | |||
958 | ||||
959 | return B_OK((int)0); | |||
960 | } | |||
961 | ||||
962 | ||||
963 | void ImageView::getCoords(BPoint *bitmap_point, uint32 *buttons,BPoint *view_point) | |||
964 | { | |||
965 | // this function converts the points using magnifying_scale | |||
966 | // to correspond to real points in buffer | |||
967 | // we also take any possible grids into account | |||
968 | BPoint point; | |||
969 | GetMouse(&point,buttons); | |||
970 | (*bitmap_point).x = floor(point.x / getMagScale()); | |||
971 | (*bitmap_point).y = floor(point.y / getMagScale()); | |||
972 | // and finally we round the point to grid units | |||
973 | (*bitmap_point) = roundToGrid(*bitmap_point); | |||
974 | ||||
975 | // Also if the view_point is not NULL put the point into it | |||
976 | if (view_point != NULL__null) { | |||
977 | view_point->x = (*bitmap_point).x*getMagScale(); | |||
978 | view_point->y = (*bitmap_point).y*getMagScale(); | |||
979 | } | |||
980 | } | |||
981 | ||||
982 | ||||
983 | void ImageView::setGrid(BPoint origin, int32 unit) | |||
984 | { | |||
985 | // here we give the grid-variables new values | |||
986 | grid_unit = (unit >= 1 ? unit : 1); | |||
987 | grid_origin = origin; | |||
988 | } | |||
989 | ||||
990 | ||||
991 | void ImageView::setMagScale(float scale) | |||
992 | { | |||
993 | // this will be used to see if the scale was actually changed | |||
994 | // and is there a need to draw the view | |||
995 | float prev_scale = magnify_scale; | |||
996 | ||||
997 | if (scale <= HS_MAX_MAG_SCALE16.0) { | |||
998 | if (scale >= HS_MIN_MAG_SCALE0.1) { | |||
999 | magnify_scale = scale; | |||
1000 | } | |||
1001 | else | |||
1002 | magnify_scale = HS_MIN_MAG_SCALE0.1; | |||
1003 | } | |||
1004 | else | |||
1005 | magnify_scale = HS_MAX_MAG_SCALE16.0; | |||
1006 | ||||
1007 | selection->ChangeMagnifyingScale(magnify_scale); | |||
1008 | ||||
1009 | ||||
1010 | // if the scale was changed and the view is on screen draw the view | |||
1011 | // also update the scrollbars | |||
1012 | if ((prev_scale != magnify_scale) && !IsHidden()) { | |||
1013 | adjustSize(); | |||
1014 | adjustPosition(); | |||
1015 | adjustScrollBars(); | |||
1016 | // we should here also draw the view | |||
1017 | Invalidate(Bounds()); | |||
1018 | } | |||
1019 | ||||
1020 | ((PaintWindow*)Window())->displayMag(magnify_scale); | |||
1021 | } | |||
1022 | ||||
1023 | ||||
1024 | BPoint ImageView::roundToGrid(BPoint point) | |||
1025 | { | |||
1026 | // here we round the coordinates of point to nearest grid-unit | |||
1027 | // this version does not take the grid_origin into account | |||
1028 | point.x = point.x - (((int)point.x) % grid_unit); | |||
1029 | point.y = point.y - (((int)point.y) % grid_unit); | |||
1030 | ||||
1031 | return point; | |||
1032 | } | |||
1033 | ||||
1034 | ||||
1035 | BRect ImageView::convertBitmapRectToView(BRect rect) | |||
1036 | { | |||
1037 | // bitmap might also have some offset that should be taken | |||
1038 | // into account | |||
1039 | ||||
1040 | // this only takes the mag_scale into account | |||
1041 | float scale = getMagScale(); | |||
1042 | ||||
1043 | if (scale > 1.0) { | |||
1044 | rect.left = rect.left * scale; | |||
1045 | rect.top = rect.top * scale; | |||
1046 | rect.right = rect.right * scale + scale - 1; | |||
1047 | rect.bottom = rect.bottom * scale + scale - 1; | |||
1048 | } | |||
1049 | else if (scale < 1.0) { | |||
1050 | rect.left = floor(rect.left * scale); | |||
1051 | rect.top = floor(rect.top * scale); | |||
1052 | rect.right = floor(rect.right * scale); | |||
1053 | rect.bottom = floor(rect.bottom * scale); | |||
1054 | } | |||
1055 | ||||
1056 | ||||
1057 | // here convert the rect to use offset | |||
1058 | //rect.OffsetBy(((Layer*)layer_list->ItemAt(current_layer_index))->Offset().LeftTop()); | |||
1059 | ||||
1060 | return rect; | |||
1061 | } | |||
1062 | ||||
1063 | BRect ImageView::convertViewRectToBitmap(BRect rect) | |||
1064 | { | |||
1065 | // It is not possible to convert a view rectangle into | |||
1066 | // a bitmap rectangle perfectly if magnifying scale is | |||
1067 | // not 1. The rectangle will be converted to the smallest | |||
1068 | // possible rectangle. Half pixels will be converted so that the | |||
1069 | // rectangle is extended. | |||
1070 | float scale = getMagScale(); | |||
1071 | ||||
1072 | BRect bitmap_rect; | |||
1073 | ||||
1074 | bitmap_rect.left = floor(rect.left / scale); | |||
1075 | bitmap_rect.top = floor(rect.top / scale); | |||
1076 | bitmap_rect.right = ceil(rect.right / scale); | |||
1077 | bitmap_rect.bottom = ceil(rect.bottom / scale); | |||
1078 | ||||
1079 | bitmap_rect = bitmap_rect & the_image->ReturnRenderedImage()->Bounds(); | |||
1080 | return bitmap_rect; | |||
1081 | } | |||
1082 | ||||
1083 | ||||
1084 | ||||
1085 | void ImageView::ActiveLayerChanged() | |||
1086 | { | |||
1087 | GUIManipulator *gui_manipulator = cast_as(fManipulator,GUIManipulator)(dynamic_cast<GUIManipulator*>(fManipulator)); | |||
1088 | ||||
1089 | if ((gui_manipulator != NULL__null) && (manipulated_layers == HS_MANIPULATE_CURRENT_LAYER'Mncl')) { | |||
1090 | gui_manipulator->Reset(selection); | |||
1091 | gui_manipulator->SetPreviewBitmap(the_image->ReturnActiveBitmap()); | |||
1092 | ||||
1093 | // We should also tell the manipulator to recalculate its preview. | |||
1094 | // This can be best achieved by sending a HS_MANIPULATOR_ADJUSTING_FINISHED | |||
1095 | // message to this view. | |||
1096 | Window()->PostMessage(HS_MANIPULATOR_ADJUSTING_FINISHED'Mafi',this); | |||
1097 | } | |||
1098 | } | |||
1099 | ||||
1100 | void ImageView::adjustSize() | |||
1101 | { | |||
1102 | if (LockLooper() == TRUE1) { | |||
1103 | // resize the view to proper size | |||
1104 | BRect bg_bounds = Parent()->Bounds(); | |||
1105 | BRect vertBounds = ScrollBar(B_VERTICAL)->Bounds(); | |||
1106 | BRect horzBounds = ScrollBar(B_HORIZONTAL)->Bounds(); | |||
1107 | ResizeTo( | |||
1108 | min_c(((bg_bounds.Width() - vertBounds.Width() - 2)>(getMagScale () * the_image->Width() - 1)?(getMagScale() * the_image-> Width() - 1):(bg_bounds.Width() - vertBounds.Width() - 2)) | |||
1109 | bg_bounds.Width() - vertBounds.Width() - 2,((bg_bounds.Width() - vertBounds.Width() - 2)>(getMagScale () * the_image->Width() - 1)?(getMagScale() * the_image-> Width() - 1):(bg_bounds.Width() - vertBounds.Width() - 2)) | |||
1110 | getMagScale() * the_image->Width() - 1)((bg_bounds.Width() - vertBounds.Width() - 2)>(getMagScale () * the_image->Width() - 1)?(getMagScale() * the_image-> Width() - 1):(bg_bounds.Width() - vertBounds.Width() - 2)), | |||
1111 | min_c(((bg_bounds.Height() - horzBounds.Height() - 2)>(getMagScale () * the_image->Height() - 1)?(getMagScale() * the_image-> Height() - 1):(bg_bounds.Height() - horzBounds.Height() - 2)) | |||
1112 | bg_bounds.Height() - horzBounds.Height() - 2,((bg_bounds.Height() - horzBounds.Height() - 2)>(getMagScale () * the_image->Height() - 1)?(getMagScale() * the_image-> Height() - 1):(bg_bounds.Height() - horzBounds.Height() - 2)) | |||
1113 | getMagScale() * the_image->Height() - 1)((bg_bounds.Height() - horzBounds.Height() - 2)>(getMagScale () * the_image->Height() - 1)?(getMagScale() * the_image-> Height() - 1):(bg_bounds.Height() - horzBounds.Height() - 2))); | |||
1114 | UnlockLooper(); | |||
1115 | } | |||
1116 | } | |||
1117 | ||||
1118 | void ImageView::adjustPosition() | |||
1119 | { | |||
1120 | if (LockLooper() == TRUE1) { | |||
1121 | BPoint top_left; | |||
1122 | BRect bg_bounds = Parent()->Bounds(); | |||
1123 | BRect vertBounds = ScrollBar(B_VERTICAL)->Bounds(); | |||
1124 | BRect horzBounds = ScrollBar(B_HORIZONTAL)->Bounds(); | |||
1125 | top_left.x = (bg_bounds.Width() - vertBounds.Width() - | |||
1126 | getMagScale()*the_image->Width()) / 2; | |||
1127 | top_left.y = (bg_bounds.Height() - horzBounds.Height() - | |||
1128 | getMagScale()*the_image->Height()) / 2; | |||
1129 | ||||
1130 | top_left.x = max_c(0,(int32)top_left.x)((0)>((int32)top_left.x)?(0):((int32)top_left.x)); | |||
1131 | top_left.y = max_c(0,(int32)top_left.y)((0)>((int32)top_left.y)?(0):((int32)top_left.y)); | |||
1132 | ||||
1133 | if (top_left != Frame().LeftTop()) | |||
1134 | MoveTo(top_left); | |||
1135 | ||||
1136 | UnlockLooper(); | |||
1137 | } | |||
1138 | } | |||
1139 | ||||
1140 | ||||
1141 | void ImageView::adjustScrollBars() | |||
1142 | { | |||
1143 | if (LockLooper() == TRUE1) { | |||
1144 | // set the horizontal bar | |||
1145 | if ((getMagScale()*the_image->Width() - (Frame().Width() + 1)) <= 0) { | |||
1146 | ScrollBar(B_HORIZONTAL)->SetRange(0,0); | |||
1147 | ScrollBar(B_HORIZONTAL)->SetProportion(1); | |||
1148 | } | |||
1149 | else { | |||
1150 | ScrollBar(B_HORIZONTAL)->SetRange(0,getMagScale()*the_image->Width() - (Frame().Width() + 1)); | |||
1151 | ScrollBar(B_HORIZONTAL)->SetProportion((Frame().Width() + 1)/(getMagScale()*the_image->Width())); | |||
1152 | } | |||
1153 | ||||
1154 | // set the vertical bar | |||
1155 | if ((getMagScale()*the_image->Height() - (Frame().Height() + 1)) <= 0) { | |||
1156 | ScrollBar(B_VERTICAL)->SetRange(0,0); | |||
1157 | ScrollBar(B_VERTICAL)->SetProportion(1); | |||
1158 | } | |||
1159 | else { | |||
1160 | ScrollBar(B_VERTICAL)->SetRange(0,getMagScale()*the_image->Height() - (Frame().Height() + 1)); | |||
1161 | ScrollBar(B_VERTICAL)->SetProportion((Frame().Height() + 1)/(getMagScale()*the_image->Height())); | |||
1162 | } | |||
1163 | ||||
1164 | UnlockLooper(); | |||
1165 | } | |||
1166 | } | |||
1167 | ||||
1168 | Selection* ImageView::GetSelection() | |||
1169 | { | |||
1170 | return selection; | |||
1171 | } | |||
1172 | ||||
1173 | void ImageView::start_thread(int32 thread_type) | |||
1174 | { | |||
1175 | thread_id a_thread = spawn_thread(enter_thread,"ImageView thread",B_NORMAL_PRIORITY10,this); | |||
1176 | if (a_thread >= 0) { | |||
1177 | resume_thread(a_thread); | |||
1178 | send_data(a_thread,thread_type,NULL__null,0); | |||
1179 | } | |||
1180 | } | |||
1181 | ||||
1182 | int32 ImageView::enter_thread(void *data) | |||
1183 | { | |||
1184 | ImageView *this_pointer = (ImageView*)data; | |||
1185 | int32 thread_type = receive_data(NULL__null,NULL__null,0); | |||
1186 | int32 err = B_OK((int)0); | |||
1187 | ||||
1188 | if (thread_type == MANIPULATOR_FINISHER_THREAD) { | |||
| ||||
1189 | acquire_sem(this_pointer->action_semaphore); | |||
1190 | } | |||
1191 | else if (acquire_sem_etc(this_pointer->action_semaphore,1,B_TIMEOUT,0) != B_OK((int)0)) { | |||
1192 | if ((thread_type == PAINTER_THREAD) || (thread_type == MANIPULATOR_MOUSE_THREAD)) | |||
1193 | release_sem(this_pointer->mouse_mutex); | |||
1194 | return B_ERROR(-1); | |||
1195 | } | |||
1196 | ||||
1197 | if (this_pointer
| |||
1198 | switch (thread_type) { | |||
1199 | case PAINTER_THREAD: | |||
1200 | err = this_pointer->PaintToolThread(); | |||
1201 | break; | |||
1202 | case MANIPULATOR_MOUSE_THREAD: | |||
1203 | err = this_pointer->ManipulatorMouseTrackerThread(); | |||
1204 | break; | |||
1205 | case MANIPULATOR_UPDATER_THREAD: | |||
1206 | err = this_pointer->GUIManipulatorUpdaterThread(); | |||
1207 | break; | |||
1208 | case MANIPULATOR_FINISHER_THREAD: | |||
1209 | err = this_pointer->ManipulatorFinisherThread(); | |||
1210 | break; | |||
1211 | default: | |||
1212 | break; | |||
1213 | } | |||
1214 | } | |||
1215 | ||||
1216 | // When the work has been done we may once again permit | |||
1217 | // the reading of the mouse. | |||
1218 | if ((thread_type == PAINTER_THREAD) || (thread_type == MANIPULATOR_MOUSE_THREAD)) | |||
1219 | release_sem(this_pointer->mouse_mutex); | |||
1220 | ||||
1221 | release_sem(this_pointer->action_semaphore); | |||
1222 | ||||
1223 | this_pointer->SetReferencePoint(BPoint(0,0),FALSE0); | |||
1224 | ||||
1225 | return err; | |||
1226 | } | |||
1227 | ||||
1228 | ||||
1229 | int32 ImageView::PaintToolThread() | |||
1230 | { | |||
1231 | uint32 buttons; | |||
1232 | BPoint point; | |||
1233 | BPoint view_point; | |||
1234 | if (LockLooper() == TRUE1) { | |||
1235 | getCoords(&point,&buttons,&view_point); | |||
1236 | UnlockLooper(); | |||
1237 | } else | |||
1238 | return B_ERROR(-1); | |||
1239 | ||||
1240 | SetReferencePoint(point,TRUE1); | |||
1241 | ||||
1242 | int32 tool_type = ToolManager::Instance().ReturnActiveToolType(); | |||
1243 | ||||
1244 | if (modifiers() & B_COMMAND_KEY) { | |||
1245 | tool_type = COLOR_SELECTOR_TOOL; | |||
1246 | } | |||
1247 | ||||
1248 | if (tool_type != TEXT_TOOL) { | |||
1249 | if (tool_type != NO_TOOL) { | |||
1250 | // When this function returns the tool has finished. This function | |||
1251 | // might not return even if the user releases the mouse-button (in | |||
1252 | // which case for example a double-click might make it return). | |||
1253 | ToolScript* script = ToolManager::Instance().StartTool(this, buttons, point, | |||
1254 | view_point, tool_type); | |||
1255 | if (script && tool_type != SELECTOR_TOOL) { | |||
1256 | const DrawingTool* tool = ToolManager::Instance().ReturnTool(tool_type); | |||
1257 | UndoEvent *new_event = undo_queue->AddUndoEvent(tool->Name(), | |||
1258 | the_image->ReturnThumbnailImage()); | |||
1259 | BList *layer_list = the_image->LayerList(); | |||
1260 | if (new_event != NULL__null) { | |||
1261 | for (int32 i=0;i<layer_list->CountItems();i++) { | |||
1262 | Layer *layer = (Layer*)layer_list->ItemAt(i); | |||
1263 | UndoAction *new_action; | |||
1264 | if (layer->IsActive() == FALSE0) | |||
1265 | new_action = new UndoAction(layer->Id()); | |||
1266 | else | |||
1267 | new_action = new UndoAction(layer->Id(), script,ToolManager::Instance().LastUpdatedRect(this)); | |||
1268 | ||||
1269 | new_event->AddAction(new_action); | |||
1270 | new_action->StoreUndo(layer->Bitmap()); | |||
1271 | } | |||
1272 | if ((new_event != NULL__null) && (new_event->IsEmpty() == TRUE1)) { | |||
1273 | undo_queue->RemoveEvent(new_event); | |||
1274 | delete new_event; | |||
1275 | } | |||
1276 | AddChange(); | |||
1277 | } | |||
1278 | else { | |||
1279 | delete script; | |||
1280 | ToolManager::Instance().LastUpdatedRect(this); | |||
1281 | } | |||
1282 | } | |||
1283 | else if (tool_type == SELECTOR_TOOL) { | |||
1284 | // Add selection-change to the undo-queue. | |||
1285 | if (!(*undo_queue->ReturnSelectionData() == *selection->ReturnSelectionData())) { | |||
1286 | const DrawingTool *used_tool = ToolManager::Instance().ReturnTool(tool_type); | |||
1287 | UndoEvent *new_event = undo_queue->AddUndoEvent(used_tool->Name(),the_image->ReturnThumbnailImage()); | |||
1288 | if (new_event != NULL__null) { | |||
1289 | new_event->SetSelectionData(undo_queue->ReturnSelectionData()); | |||
1290 | undo_queue->SetSelectionData(selection->ReturnSelectionData()); | |||
1291 | } | |||
1292 | } | |||
1293 | ||||
1294 | // Tell the selection to start drawing itself. | |||
1295 | selection->StartDrawing(this,magnify_scale); | |||
1296 | } | |||
1297 | return B_OK((int)0); | |||
1298 | } | |||
1299 | } else { | |||
1300 | if (ManipulatorServer* server = ManipulatorServer::Instance()) { | |||
1301 | if (!fManipulator) { | |||
1302 | if (TextManipulator* manipulator = dynamic_cast<TextManipulator*> | |||
1303 | (server->ManipulatorFor(TEXT_MANIPULATOR))) { | |||
1304 | manipulator->SetStartingPoint(point); | |||
1305 | manipulated_layers = HS_MANIPULATE_CURRENT_LAYER'Mncl'; | |||
1306 | manipulator->SetPreviewBitmap(the_image->ReturnActiveBitmap()); | |||
1307 | ||||
1308 | PaintWindow* window = dynamic_cast<PaintWindow*> (Window()); | |||
1309 | if (window && LockLooper()) { | |||
1310 | window->SetHelpString(manipulator->ReturnHelpString(), | |||
1311 | HS_TOOL_HELP_MESSAGE'TolM'); | |||
1312 | UnlockLooper(); | |||
1313 | } | |||
1314 | ||||
1315 | BString name = ReturnProjectName(); | |||
1316 | name << ": " << manipulator->ReturnName(); | |||
1317 | ||||
1318 | manipulator_window = new ManipulatorWindow(BRect(100, 100, | |||
1319 | 200.0, 200.0), manipulator->MakeConfigurationView(this), | |||
1320 | name.String(), window, this); | |||
1321 | ||||
1322 | if (window) { | |||
1323 | window->PostMessage(HS_MANIPULATOR_ADJUSTING_FINISHED'Mafi', | |||
1324 | this); | |||
1325 | } | |||
1326 | ||||
1327 | fManipulator = manipulator; | |||
1328 | cursor_mode = MANIPULATOR_CURSOR_MODE; | |||
1329 | ||||
1330 | SetCursor(); | |||
1331 | return B_OK((int)0); | |||
1332 | } | |||
1333 | } | |||
1334 | } | |||
1335 | } | |||
1336 | return B_ERROR(-1); | |||
1337 | } | |||
1338 | ||||
1339 | ||||
1340 | int32 ImageView::ManipulatorMouseTrackerThread() | |||
1341 | { | |||
1342 | GUIManipulator *gui_manipulator = cast_as(fManipulator,GUIManipulator)(dynamic_cast<GUIManipulator*>(fManipulator)); | |||
1343 | if (gui_manipulator == NULL__null) | |||
1344 | return B_ERROR(-1); | |||
1345 | ||||
1346 | ||||
1347 | BPoint point; | |||
1348 | uint32 buttons; | |||
1349 | if (LockLooper() == TRUE1) { | |||
1350 | getCoords(&point,&buttons); | |||
1351 | UnlockLooper(); | |||
1352 | } else | |||
1353 | return B_ERROR(-1); | |||
1354 | ||||
1355 | int32 preview_quality; | |||
1356 | bool first_call_to_mouse_down = TRUE1; | |||
1357 | BRegion *updated_region = new BRegion(); | |||
1358 | ||||
1359 | float number_of_frames = 0; | |||
1360 | float time = system_time(); | |||
1361 | while (buttons) { | |||
1362 | updated_region->MakeEmpty(); | |||
1363 | if (LockLooper() == TRUE1) { | |||
1364 | gui_manipulator->MouseDown(point,buttons,this,first_call_to_mouse_down); | |||
1365 | first_call_to_mouse_down = FALSE0; | |||
1366 | preview_quality = gui_manipulator->PreviewBitmap(selection,FALSE0,updated_region); | |||
1367 | if (preview_quality != DRAW_NOTHING) { | |||
1368 | if ((preview_quality != DRAW_ONLY_GUI) && (updated_region->Frame().IsValid())) { | |||
1369 | if (manipulated_layers != HS_MANIPULATE_ALL_LAYERS'Mnal') { | |||
1370 | the_image->RenderPreview(updated_region->Frame(),preview_quality); | |||
1371 | } | |||
1372 | else { | |||
1373 | the_image->MultiplyRenderedImagePixels(preview_quality); | |||
1374 | } | |||
1375 | for (int32 i=0;i<updated_region->CountRects();i++) | |||
1376 | Draw(convertBitmapRectToView(updated_region->RectAt(i))); | |||
1377 | } | |||
1378 | else if (preview_quality == DRAW_ONLY_GUI) { | |||
1379 | DrawManipulatorGUI(TRUE1); | |||
1380 | selection->Draw(); | |||
1381 | Flush(); | |||
1382 | } | |||
1383 | number_of_frames++; | |||
1384 | } | |||
1385 | else { | |||
1386 | snooze(50 * 1000); | |||
1387 | } | |||
1388 | getCoords(&point,&buttons); | |||
1389 | UnlockLooper(); | |||
1390 | } | |||
1391 | } | |||
1392 | ||||
1393 | time = system_time() - time; | |||
1394 | time = time / 1000000.0; | |||
1395 | ||||
1396 | // printf("Frames per second: %f\n",number_of_frames/time); | |||
1397 | ||||
1398 | cursor_mode = BLOCKING_CURSOR_MODE; | |||
1399 | SetCursor(); | |||
1400 | ||||
1401 | updated_region->Set(BRect(0,0,-1,-1)); | |||
1402 | preview_quality = gui_manipulator->PreviewBitmap(selection,TRUE1,updated_region); | |||
1403 | if (preview_quality != DRAW_NOTHING) { | |||
1404 | if ((preview_quality != DRAW_ONLY_GUI) && (updated_region->Frame().IsValid())) { | |||
1405 | if (manipulated_layers != HS_MANIPULATE_ALL_LAYERS'Mnal') { | |||
1406 | the_image->RenderPreview(updated_region->Frame(),preview_quality); | |||
1407 | } | |||
1408 | else | |||
1409 | the_image->MultiplyRenderedImagePixels(preview_quality); | |||
1410 | ||||
1411 | if (LockLooper() == TRUE1) { | |||
1412 | for (int32 i=0;i<updated_region->CountRects();i++) | |||
1413 | Draw(convertBitmapRectToView(updated_region->RectAt(i))); | |||
1414 | UnlockLooper(); | |||
1415 | } | |||
1416 | } | |||
1417 | else if (preview_quality == DRAW_ONLY_GUI) { | |||
1418 | if (LockLooper() == TRUE1) { | |||
1419 | DrawManipulatorGUI(TRUE1); | |||
1420 | selection->Draw(); | |||
1421 | Flush(); | |||
1422 | UnlockLooper(); | |||
1423 | } | |||
1424 | } | |||
1425 | } | |||
1426 | ||||
1427 | cursor_mode = MANIPULATOR_CURSOR_MODE; | |||
1428 | SetCursor(); | |||
1429 | ||||
1430 | delete updated_region; | |||
1431 | return B_OK((int)0); | |||
1432 | } | |||
1433 | ||||
1434 | ||||
1435 | int32 ImageView::GUIManipulatorUpdaterThread() | |||
1436 | { | |||
1437 | GUIManipulator *gui_manipulator = cast_as(fManipulator,GUIManipulator)(dynamic_cast<GUIManipulator*>(fManipulator)); | |||
1438 | if (gui_manipulator == NULL__null) | |||
1439 | return B_ERROR(-1); | |||
1440 | ||||
1441 | ||||
1442 | int32 preview_quality = 0; | |||
1443 | int32 lowest_quality = 0; | |||
1444 | BRegion *updated_region = new BRegion(); | |||
1445 | ||||
1446 | float number_of_frames = 0; | |||
1447 | ||||
1448 | while (continue_manipulator_updating) { | |||
1449 | if (LockLooper() == TRUE1) { | |||
1450 | preview_quality = gui_manipulator->PreviewBitmap(selection,FALSE0,updated_region); | |||
1451 | lowest_quality = max_c(lowest_quality,preview_quality)((lowest_quality)>(preview_quality)?(lowest_quality):(preview_quality )); | |||
1452 | ||||
1453 | if ((preview_quality != DRAW_NOTHING) && (updated_region->Frame().IsValid())) { | |||
1454 | if (preview_quality != DRAW_ONLY_GUI) { | |||
1455 | if (manipulated_layers != HS_MANIPULATE_ALL_LAYERS'Mnal') { | |||
1456 | the_image->RenderPreview(updated_region->Frame(),preview_quality); | |||
1457 | } | |||
1458 | else | |||
1459 | the_image->MultiplyRenderedImagePixels(preview_quality); | |||
1460 | ||||
1461 | for (int32 i=0;i<updated_region->CountRects();i++) | |||
1462 | Draw(convertBitmapRectToView(updated_region->RectAt(i))); | |||
1463 | } | |||
1464 | else if (preview_quality == DRAW_ONLY_GUI) { | |||
1465 | DrawManipulatorGUI(TRUE1); | |||
1466 | selection->Draw(); | |||
1467 | Flush(); | |||
1468 | } | |||
1469 | number_of_frames++; | |||
1470 | } | |||
1471 | else { | |||
1472 | snooze(50 * 1000); | |||
1473 | } | |||
1474 | UnlockLooper(); | |||
1475 | } | |||
1476 | if (preview_quality == lowest_quality) { | |||
1477 | snooze(50 * 1000); | |||
1478 | } | |||
1479 | else { | |||
1480 | snooze(20 * 1000); | |||
1481 | } | |||
1482 | } | |||
1483 | ||||
1484 | updated_region->Set(BRect(0,0,-1,-1)); | |||
1485 | ||||
1486 | cursor_mode = BLOCKING_CURSOR_MODE; | |||
1487 | SetCursor(); | |||
1488 | ||||
1489 | preview_quality = gui_manipulator->PreviewBitmap(selection,TRUE1,updated_region); | |||
1490 | ||||
1491 | ||||
1492 | if (preview_quality != DRAW_NOTHING) { | |||
1493 | if ((preview_quality != DRAW_ONLY_GUI) && (updated_region->Frame().IsValid())) { | |||
1494 | if (manipulated_layers != HS_MANIPULATE_ALL_LAYERS'Mnal') { | |||
1495 | the_image->RenderPreview(updated_region->Frame(),preview_quality); | |||
1496 | } | |||
1497 | else | |||
1498 | the_image->MultiplyRenderedImagePixels(preview_quality); | |||
1499 | ||||
1500 | if (LockLooper() == TRUE1) { | |||
1501 | for (int32 i=0;i<updated_region->CountRects();i++) | |||
1502 | Draw(convertBitmapRectToView(updated_region->RectAt(i))); | |||
1503 | UnlockLooper(); | |||
1504 | } | |||
1505 | } | |||
1506 | else if (preview_quality == DRAW_ONLY_GUI){ | |||
1507 | if (LockLooper() == TRUE1) { | |||
1508 | DrawManipulatorGUI(TRUE1); | |||
1509 | selection->Draw(); | |||
1510 | Flush(); | |||
1511 | UnlockLooper(); | |||
1512 | } | |||
1513 | } | |||
1514 | } | |||
1515 | ||||
1516 | cursor_mode = MANIPULATOR_CURSOR_MODE; | |||
1517 | SetCursor(); | |||
1518 | ||||
1519 | delete updated_region; | |||
1520 | return B_OK((int)0); | |||
1521 | } | |||
1522 | ||||
1523 | ||||
1524 | int32 ImageView::ManipulatorFinisherThread() | |||
1525 | { | |||
1526 | if (fManipulator == NULL__null) { | |||
1527 | if (manipulator_finishing_message != NULL__null) { | |||
1528 | if (LockLooper() == TRUE1) { | |||
1529 | Window()->PostMessage(manipulator_finishing_message,this); | |||
1530 | delete manipulator_finishing_message; | |||
1531 | manipulator_finishing_message = NULL__null; | |||
1532 | UnlockLooper(); | |||
1533 | } | |||
1534 | } | |||
1535 | return B_ERROR(-1); | |||
1536 | } | |||
1537 | cursor_mode = BLOCKING_CURSOR_MODE; | |||
1538 | SetCursor(); | |||
1539 | ||||
1540 | // Here we should set up the status-bar | |||
1541 | BStatusBar *status_bar = ((PaintWindow*)Window())->ReturnStatusView()->DisplayProgressIndicator(); | |||
1542 | if (status_bar != NULL__null) { | |||
1543 | if (LockLooper() == TRUE1) { | |||
1544 | status_bar->Reset(); | |||
1545 | status_bar->SetText(B_TRANSLATE("Finishing")BLocaleRoster::Default()->GetCatalog()->GetString(("Finishing" ), "ImageView")); | |||
1546 | UnlockLooper(); | |||
1547 | } | |||
1548 | } | |||
1549 | GUIManipulator *gui_manipulator = cast_as(fManipulator,GUIManipulator)(dynamic_cast<GUIManipulator*>(fManipulator)); | |||
1550 | UndoEvent *new_event = NULL__null; | |||
1551 | ||||
1552 | try { | |||
1553 | if (manipulated_layers == HS_MANIPULATE_CURRENT_LAYER'Mncl') { | |||
1554 | BBitmap *buffer = the_image->ReturnActiveBitmap(); | |||
1555 | BBitmap *new_buffer = NULL__null; | |||
1556 | if (gui_manipulator != NULL__null) { | |||
1557 | ManipulatorSettings *settings = gui_manipulator->ReturnSettings(); | |||
1558 | new_buffer = gui_manipulator->ManipulateBitmap(settings,buffer,selection,status_bar); | |||
1559 | delete settings; | |||
1560 | } | |||
1561 | else { | |||
1562 | new_buffer = fManipulator->ManipulateBitmap(buffer,selection,status_bar); | |||
1563 | } | |||
1564 | ||||
1565 | Layer *the_layer = the_image->ReturnActiveLayer(); | |||
1566 | if (new_buffer && new_buffer != buffer) | |||
1567 | the_layer->ChangeBitmap(new_buffer); | |||
1568 | ||||
1569 | new_event = undo_queue->AddUndoEvent(fManipulator->ReturnName(), | |||
1570 | the_image->ReturnThumbnailImage()); | |||
1571 | if (new_event != NULL__null) { | |||
1572 | BList *layer_list = the_image->LayerList(); | |||
1573 | for (int32 i=0;i<layer_list->CountItems();i++) { | |||
1574 | Layer *layer = (Layer*)layer_list->ItemAt(i); | |||
1575 | ||||
1576 | UndoAction *new_action; | |||
1577 | if ((layer != the_layer) || (new_buffer == NULL__null)) | |||
1578 | new_action = new UndoAction(layer->Id()); | |||
1579 | else { | |||
1580 | BRegion affected_region(new_buffer->Bounds()); | |||
1581 | new_action = new UndoAction(layer->Id(), | |||
1582 | fManipulator->ReturnSettings(), | |||
1583 | new_buffer->Bounds(), | |||
1584 | (manipulator_type)manip_type, add_on_id); | |||
1585 | } | |||
1586 | new_event->AddAction(new_action); | |||
1587 | new_action->StoreUndo(layer->Bitmap()); | |||
1588 | } | |||
1589 | } | |||
1590 | } | |||
1591 | else { | |||
1592 | // Do all the layers. | |||
1593 | // Here we record the dimensions of all the bitmaps. If the | |||
1594 | // dimensions change the composite bitmap should be changed to | |||
1595 | // smallest layer dimension. | |||
1596 | ||||
1597 | BList* layer_list = the_image->LayerList(); | |||
1598 | int32 layerCount = layer_list->CountItems(); | |||
1599 | if (status_bar
| |||
1600 | status_bar->SetMaxValue(layerCount * 100); | |||
1601 | ||||
1602 | new_event = undo_queue->AddUndoEvent(fManipulator->ReturnName(), | |||
1603 | the_image->ReturnThumbnailImage()); | |||
1604 | ||||
1605 | for (int32 i = 0; i < layerCount; ++i) { | |||
1606 | if (LockLooper()) { | |||
1607 | BString format(B_TRANSLATE("Layer %ld / %ld")BLocaleRoster::Default()->GetCatalog()->GetString(("Layer %ld / %ld" ), "ImageView")); | |||
1608 | BString text; | |||
1609 | text.SetToFormat(format, i + 1, layerCount); | |||
1610 | status_bar->SetTrailingText(text); | |||
1611 | UnlockLooper(); | |||
1612 | } | |||
1613 | ||||
1614 | Layer* the_layer = static_cast<Layer*> (layer_list->ItemAt(i)); | |||
1615 | BBitmap *buffer = the_layer->Bitmap(); | |||
1616 | BBitmap *new_buffer; | |||
1617 | if (gui_manipulator != NULL__null) { | |||
1618 | ManipulatorSettings *settings = gui_manipulator->ReturnSettings(); | |||
1619 | new_buffer = gui_manipulator->ManipulateBitmap(settings,buffer,selection,status_bar); | |||
1620 | delete settings; | |||
1621 | } | |||
1622 | else { | |||
1623 | new_buffer = fManipulator->ManipulateBitmap(buffer,selection,status_bar); | |||
1624 | } | |||
1625 | ||||
1626 | if (new_buffer && new_buffer != buffer) | |||
1627 | the_layer->ChangeBitmap(new_buffer); | |||
1628 | ||||
1629 | if (new_event != NULL__null) { | |||
1630 | if (new_buffer != NULL__null) { | |||
1631 | BRegion affected_region(new_buffer->Bounds()); | |||
1632 | UndoAction *new_action; | |||
1633 | new_action = new UndoAction(the_layer->Id(),fManipulator->ReturnSettings(),new_buffer->Bounds(),(manipulator_type)manip_type,add_on_id); | |||
1634 | ||||
1635 | new_event->AddAction(new_action); | |||
1636 | new_action->StoreUndo(the_layer->Bitmap()); | |||
1637 | thread_id a_thread = spawn_thread(Layer::CreateMiniatureImage,"create mini picture",B_LOW_PRIORITY5,the_layer); | |||
1638 | resume_thread(a_thread); | |||
1639 | } | |||
1640 | else { | |||
1641 | new_event->AddAction(new UndoAction(the_layer->Id())); | |||
1642 | } | |||
1643 | } | |||
1644 | } | |||
1645 | } | |||
1646 | } | |||
1647 | catch (std::bad_alloc e) { | |||
1648 | ShowAlert(CANNOT_FINISH_MANIPULATOR_ALERT); | |||
1649 | // The manipulator should be asked to reset the preview-bitmap, if it is | |||
1650 | // a GUIManipulator. | |||
1651 | if (gui_manipulator != NULL__null) { | |||
1652 | gui_manipulator->Reset(selection); | |||
1653 | } | |||
1654 | } | |||
1655 | ||||
1656 | manipulated_layers = HS_MANIPULATE_NO_LAYER'Mnnl'; | |||
1657 | ||||
1658 | ||||
1659 | // If the added UndoEvent is empty then destroy it. | |||
1660 | if ((new_event != NULL__null) && (new_event->IsEmpty() == TRUE1)) { | |||
1661 | undo_queue->RemoveEvent(new_event); | |||
1662 | delete new_event; | |||
1663 | } | |||
1664 | ||||
1665 | the_image->SetImageSize(); | |||
1666 | the_image->Render(); | |||
1667 | ||||
1668 | // also recalculate the selection | |||
1669 | selection->Recalculate(); | |||
1670 | ||||
1671 | // Change the selection for the undo-queue if necessary. | |||
1672 | if ((new_event
| |||
1673 | new_event->SetSelectionData(undo_queue->ReturnSelectionData()); | |||
| ||||
1674 | undo_queue->SetSelectionData(selection->ReturnSelectionData()); | |||
1675 | } | |||
1676 | ||||
1677 | // Store the manipulator settings. | |||
1678 | if (ManipulatorServer* server = ManipulatorServer::Instance()) | |||
1679 | server->StoreManipulatorSettings(fManipulator); | |||
1680 | ||||
1681 | ||||
1682 | // Finally return the window to normal state and redisplay it. | |||
1683 | if (LockLooper() == true) { | |||
1684 | ((PaintWindow*)Window())->ReturnStatusView()->DisplayToolsAndColors(); | |||
1685 | ||||
1686 | Invalidate(); | |||
1687 | UnlockLooper(); | |||
1688 | } | |||
1689 | ||||
1690 | // The manipulator has finished, now finish the manipulator | |||
1691 | delete fManipulator; | |||
1692 | fManipulator = NULL__null; | |||
1693 | ||||
1694 | cursor_mode = NORMAL_CURSOR_MODE; | |||
1695 | SetCursor(); | |||
1696 | ||||
1697 | if (manipulator_finishing_message != NULL__null) { | |||
1698 | if (LockLooper() == TRUE1) { | |||
1699 | Window()->PostMessage(manipulator_finishing_message,this); | |||
1700 | delete manipulator_finishing_message; | |||
1701 | manipulator_finishing_message = NULL__null; | |||
1702 | UnlockLooper(); | |||
1703 | } | |||
1704 | } | |||
1705 | ||||
1706 | ||||
1707 | return B_OK((int)0); | |||
1708 | } | |||
1709 | ||||
1710 | ||||
1711 | ||||
1712 | ||||
1713 | void ImageView::Undo() | |||
1714 | { | |||
1715 | if (acquire_sem_etc(action_semaphore,1,B_TIMEOUT,0) == B_OK((int)0)) { | |||
1716 | // If there is a GUI-manipulator, it should reset the bitmap before undo can be done. | |||
1717 | cursor_mode = BLOCKING_CURSOR_MODE; | |||
1718 | SetCursor(); | |||
1719 | ||||
1720 | GUIManipulator *gui_manipulator = cast_as(fManipulator,GUIManipulator)(dynamic_cast<GUIManipulator*>(fManipulator)); | |||
1721 | if (gui_manipulator != NULL__null) { | |||
1722 | gui_manipulator->Reset(selection); | |||
1723 | } | |||
1724 | ||||
1725 | UndoEvent *event = undo_queue->Undo(); | |||
1726 | if (event != NULL__null) { | |||
1727 | if (event->IsEmpty() == FALSE0) { | |||
1728 | the_image->UpdateImageStructure(event); | |||
1729 | ||||
1730 | cursor_mode = NORMAL_CURSOR_MODE; | |||
1731 | // After the undo, the current buffer might have changed and the | |||
1732 | // possible gui_manipulator should be informed about it. | |||
1733 | if (gui_manipulator != NULL__null) { | |||
1734 | gui_manipulator->SetPreviewBitmap(the_image->ReturnActiveBitmap()); | |||
1735 | // We should also tell the manipulator to recalculate its preview. | |||
1736 | Window()->PostMessage(HS_MANIPULATOR_ADJUSTING_FINISHED'Mafi',this); | |||
1737 | cursor_mode = MANIPULATOR_CURSOR_MODE; | |||
1738 | } | |||
1739 | LayerWindow::ActiveWindowChanged(Window(),the_image->LayerList(),the_image->ReturnThumbnailImage()); | |||
1740 | AddChange(); // Removing a change here is not a good thing | |||
1741 | } | |||
1742 | ||||
1743 | if (event->ReturnSelectionData() != NULL__null) { | |||
1744 | SelectionData *data = new SelectionData(event->ReturnSelectionData()); | |||
1745 | event->SetSelectionData(selection->ReturnSelectionData()); | |||
1746 | selection->SetSelectionData(data); | |||
1747 | ||||
1748 | undo_queue->SetSelectionData(data); | |||
1749 | delete data; | |||
1750 | } | |||
1751 | ||||
1752 | Invalidate(); | |||
1753 | } | |||
1754 | ||||
1755 | if (gui_manipulator != NULL__null) | |||
1756 | cursor_mode = MANIPULATOR_CURSOR_MODE; | |||
1757 | else | |||
1758 | cursor_mode = NORMAL_CURSOR_MODE; | |||
1759 | ||||
1760 | SetCursor(); | |||
1761 | ||||
1762 | release_sem(action_semaphore); | |||
1763 | } | |||
1764 | } | |||
1765 | ||||
1766 | ||||
1767 | ||||
1768 | void ImageView::Redo() | |||
1769 | { | |||
1770 | if (acquire_sem_etc(action_semaphore,1,B_TIMEOUT,0) == B_OK((int)0)) { | |||
1771 | // If there is a GUI-manipulator, it should reset the bitmap before redo | |||
1772 | // can be done. | |||
1773 | GUIManipulator *gui_manipulator = cast_as(fManipulator,GUIManipulator)(dynamic_cast<GUIManipulator*>(fManipulator)); | |||
1774 | if (gui_manipulator != NULL__null) { | |||
1775 | gui_manipulator->Reset(selection); | |||
1776 | } | |||
1777 | ||||
1778 | UndoEvent *event = undo_queue->Redo(); | |||
1779 | if (event != NULL__null) { | |||
1780 | if (event->IsEmpty() == FALSE0) { | |||
1781 | the_image->UpdateImageStructure(event); | |||
1782 | ||||
1783 | // After the redo, the current buffer might have changed and the | |||
1784 | // possible gui_manipulator should be informed about it. | |||
1785 | if (gui_manipulator != NULL__null) { | |||
1786 | gui_manipulator->SetPreviewBitmap(the_image->ReturnActiveBitmap()); | |||
1787 | // We should also tell the manipulator to recalculate its preview. | |||
1788 | Window()->PostMessage(HS_MANIPULATOR_ADJUSTING_FINISHED'Mafi',this); | |||
1789 | } | |||
1790 | ||||
1791 | LayerWindow::ActiveWindowChanged(Window(),the_image->LayerList(),the_image->ReturnThumbnailImage()); | |||
1792 | AddChange(); | |||
1793 | } | |||
1794 | if (event->ReturnSelectionData() != NULL__null) { | |||
1795 | SelectionData *data = new SelectionData(event->ReturnSelectionData()); | |||
1796 | event->SetSelectionData(selection->ReturnSelectionData()); | |||
1797 | selection->SetSelectionData(data); | |||
1798 | ||||
1799 | undo_queue->SetSelectionData(data); | |||
1800 | delete data; | |||
1801 | } | |||
1802 | ||||
1803 | Invalidate(); | |||
1804 | } | |||
1805 | ||||
1806 | release_sem(action_semaphore); | |||
1807 | } | |||
1808 | } | |||
1809 | ||||
1810 | status_t | |||
1811 | ImageView::DoCopyOrCut(int32 layers,bool cut) | |||
1812 | { | |||
1813 | if (acquire_sem_etc(action_semaphore,1,B_TIMEOUT,0) == B_OK((int)0)) { | |||
1814 | BBitmap *buffer; | |||
1815 | BRect* offset; | |||
1816 | bool ok_to_archive = TRUE1; | |||
1817 | if (layers == HS_MANIPULATE_CURRENT_LAYER'Mncl') | |||
1818 | buffer = the_image->ReturnActiveBitmap(); | |||
1819 | else | |||
1820 | buffer = the_image->ReturnRenderedImage(); | |||
1821 | BMessage *bitmap_archive = new BMessage(); | |||
1822 | if (selection->IsEmpty() == TRUE1) { | |||
1823 | if (buffer->Archive(bitmap_archive) != B_OK((int)0)) | |||
1824 | ok_to_archive = FALSE0; | |||
1825 | } | |||
1826 | else { | |||
1827 | BRect selection_bounds = selection->GetBoundingRect(); | |||
1828 | selection_bounds.left = floor(selection_bounds.left); | |||
1829 | selection_bounds.top = floor(selection_bounds.top); | |||
1830 | selection_bounds.right = ceil(selection_bounds.right); | |||
1831 | selection_bounds.bottom = ceil(selection_bounds.bottom); | |||
1832 | selection_bounds = selection_bounds & buffer->Bounds(); | |||
1833 | BRect bounds = selection_bounds; | |||
1834 | ||||
1835 | bounds.OffsetTo(0,0); | |||
1836 | BBitmap *to_be_archived = new BBitmap(bounds,B_RGBA32,0); //stargater, Pete | |||
1837 | uint32 *target_bits = (uint32*)to_be_archived->Bits(); | |||
1838 | int32 bits_length = to_be_archived->BitsLength()/4; | |||
1839 | union { | |||
1840 | uint8 bytes[4]; | |||
1841 | uint32 word; | |||
1842 | } color; | |||
1843 | color.bytes[0] = 0xFF; | |||
1844 | color.bytes[1] = 0xFF; | |||
1845 | color.bytes[2] = 0xFF; | |||
1846 | color.bytes[3] = 0x00; | |||
1847 | ||||
1848 | ||||
1849 | for (int32 i=0;i<bits_length;i++) { | |||
1850 | *target_bits++ = color.word; | |||
1851 | } | |||
1852 | target_bits = (uint32*)to_be_archived->Bits(); | |||
1853 | int32 left = (int32)selection_bounds.left; | |||
1854 | int32 right = (int32)selection_bounds.right; | |||
1855 | int32 top = (int32)selection_bounds.top; | |||
1856 | int32 bottom = (int32)selection_bounds.bottom; | |||
1857 | ||||
1858 | uint32 *source_bits = (uint32*)buffer->Bits(); | |||
1859 | int32 source_bpr = buffer->BytesPerRow()/4; | |||
1860 | ||||
1861 | for (int32 y=top;y<=bottom;y++) { | |||
1862 | for (int32 x=left;x<=right;x++) { | |||
1863 | if (selection->ContainsPoint(x,y)) | |||
1864 | *target_bits = *(source_bits + x + y*source_bpr); | |||
1865 | ||||
1866 | target_bits++; | |||
1867 | } | |||
1868 | } | |||
1869 | if (to_be_archived->Archive(bitmap_archive) != B_OK((int)0)) | |||
1870 | ok_to_archive = FALSE0; | |||
1871 | ||||
1872 | delete to_be_archived; | |||
1873 | } | |||
1874 | ||||
1875 | if (ok_to_archive == TRUE1) { | |||
1876 | be_clipboard->Lock(); | |||
1877 | be_clipboard->Clear(); | |||
1878 | BMessage *clipboard_message = be_clipboard->Data(); | |||
1879 | clipboard_message->AddMessage("image/bitmap",bitmap_archive); | |||
1880 | if (selection->IsEmpty() == FALSE0) | |||
1881 | clipboard_message->AddRect("offset", selection->GetBoundingRect()); | |||
1882 | be_clipboard->Commit(); | |||
1883 | be_clipboard->Unlock(); | |||
1884 | delete bitmap_archive; | |||
1885 | } | |||
1886 | if (cut == TRUE1) { | |||
1887 | if (layers == HS_MANIPULATE_CURRENT_LAYER'Mncl') | |||
1888 | Window()->PostMessage(HS_CLEAR_LAYER'Clla',this); | |||
1889 | else | |||
1890 | Window()->PostMessage(HS_CLEAR_CANVAS'Clcv',this); | |||
1891 | } | |||
1892 | ||||
1893 | release_sem(action_semaphore); | |||
1894 | return B_OK((int)0); | |||
1895 | } | |||
1896 | else | |||
1897 | return B_ERROR(-1); | |||
1898 | } | |||
1899 | ||||
1900 | ||||
1901 | status_t | |||
1902 | ImageView::DoPaste() | |||
1903 | { | |||
1904 | be_clipboard->Lock(); | |||
1905 | BMessage *clipboard_message = be_clipboard->Data(); | |||
1906 | if (clipboard_message != NULL__null) { | |||
1907 | BMessage *bitmap_message = new BMessage(); | |||
1908 | if (clipboard_message->FindMessage("image/bitmap",bitmap_message) == B_OK((int)0)) { | |||
1909 | if (bitmap_message != NULL__null) { | |||
1910 | BBitmap *pasted_bitmap = new BBitmap(bitmap_message); | |||
1911 | BRect offset; | |||
1912 | clipboard_message->FindRect("offset", &offset); | |||
1913 | delete bitmap_message; | |||
1914 | if ((pasted_bitmap != NULL__null) && (pasted_bitmap->IsValid() == TRUE1)) { | |||
1915 | try { | |||
1916 | if (the_image->AddLayer(pasted_bitmap, NULL__null, TRUE1, | |||
1917 | 1.0, &offset) != NULL__null) { | |||
1918 | // delete pasted_bitmap; | |||
1919 | Invalidate(); | |||
1920 | LayerWindow::ActiveWindowChanged(Window(), | |||
1921 | the_image->LayerList(), | |||
1922 | the_image->ReturnThumbnailImage()); | |||
1923 | AddChange(); | |||
1924 | } | |||
1925 | } | |||
1926 | catch (std::bad_alloc e) { | |||
1927 | ShowAlert(CANNOT_ADD_LAYER_ALERT); | |||
1928 | } | |||
1929 | } | |||
1930 | } | |||
1931 | } else | |||
1932 | delete bitmap_message; | |||
1933 | } | |||
1934 | be_clipboard->Unlock(); | |||
1935 | return B_OK((int)0); | |||
1936 | } | |||
1937 | ||||
1938 | ||||
1939 | ||||
1940 | status_t ImageView::ShowAlert(int32 alert) | |||
1941 | { | |||
1942 | const char *text; | |||
1943 | switch (alert) { | |||
1944 | case CANNOT_ADD_LAYER_ALERT: | |||
1945 | text = B_TRANSLATE("Not enough free memory to add a layer ."\BLocaleRoster::Default()->GetCatalog()->GetString(("Not enough free memory to add a layer ." "You can free more memory by disabling the undo and closing other images. It is also a good idea " "to save the image now because running out of memory later on might make saving difficult or " "impossible. I am very sorry about this inconvenience."), "ImageView" ) | |||
1946 | "You can free more memory by disabling the undo and closing other images. It is also a good idea "\BLocaleRoster::Default()->GetCatalog()->GetString(("Not enough free memory to add a layer ." "You can free more memory by disabling the undo and closing other images. It is also a good idea " "to save the image now because running out of memory later on might make saving difficult or " "impossible. I am very sorry about this inconvenience."), "ImageView" ) | |||
1947 | "to save the image now because running out of memory later on might make saving difficult or "\BLocaleRoster::Default()->GetCatalog()->GetString(("Not enough free memory to add a layer ." "You can free more memory by disabling the undo and closing other images. It is also a good idea " "to save the image now because running out of memory later on might make saving difficult or " "impossible. I am very sorry about this inconvenience."), "ImageView" ) | |||
1948 | "impossible. I am very sorry about this inconvenience.")BLocaleRoster::Default()->GetCatalog()->GetString(("Not enough free memory to add a layer ." "You can free more memory by disabling the undo and closing other images. It is also a good idea " "to save the image now because running out of memory later on might make saving difficult or " "impossible. I am very sorry about this inconvenience."), "ImageView" ); | |||
1949 | break; | |||
1950 | case CANNOT_START_MANIPULATOR_ALERT: | |||
1951 | text = B_TRANSLATE("Not enough free memory to start the effect you requested. You may close other images and try again. "\BLocaleRoster::Default()->GetCatalog()->GetString(("Not enough free memory to start the effect you requested. You may close other images and try again. " "Also shortening the depth of undo or disabling undo altogether helps in achieving more memory. " "If you have other applications running, closing them gives you more free memory. " "It is also a good idea to save your work at this point, because if the memory runs out completely " "saving might become impossible. I am very sorry about this inconvenience." ), "ImageView") | |||
1952 | "Also shortening the depth of undo or disabling undo altogether helps in achieving more memory. "\BLocaleRoster::Default()->GetCatalog()->GetString(("Not enough free memory to start the effect you requested. You may close other images and try again. " "Also shortening the depth of undo or disabling undo altogether helps in achieving more memory. " "If you have other applications running, closing them gives you more free memory. " "It is also a good idea to save your work at this point, because if the memory runs out completely " "saving might become impossible. I am very sorry about this inconvenience." ), "ImageView") | |||
1953 | "If you have other applications running, closing them gives you more free memory. "\BLocaleRoster::Default()->GetCatalog()->GetString(("Not enough free memory to start the effect you requested. You may close other images and try again. " "Also shortening the depth of undo or disabling undo altogether helps in achieving more memory. " "If you have other applications running, closing them gives you more free memory. " "It is also a good idea to save your work at this point, because if the memory runs out completely " "saving might become impossible. I am very sorry about this inconvenience." ), "ImageView") | |||
1954 | "It is also a good idea to save your work at this point, because if the memory runs out completely "\BLocaleRoster::Default()->GetCatalog()->GetString(("Not enough free memory to start the effect you requested. You may close other images and try again. " "Also shortening the depth of undo or disabling undo altogether helps in achieving more memory. " "If you have other applications running, closing them gives you more free memory. " "It is also a good idea to save your work at this point, because if the memory runs out completely " "saving might become impossible. I am very sorry about this inconvenience." ), "ImageView") | |||
1955 | "saving might become impossible. I am very sorry about this inconvenience.")BLocaleRoster::Default()->GetCatalog()->GetString(("Not enough free memory to start the effect you requested. You may close other images and try again. " "Also shortening the depth of undo or disabling undo altogether helps in achieving more memory. " "If you have other applications running, closing them gives you more free memory. " "It is also a good idea to save your work at this point, because if the memory runs out completely " "saving might become impossible. I am very sorry about this inconvenience." ), "ImageView"); | |||
1956 | break; | |||
1957 | ||||
1958 | case CANNOT_FINISH_MANIPULATOR_ALERT: | |||
1959 | text = B_TRANSLATE("Not enough free memory to finish the effect you requested. You may close other images and try again. "\BLocaleRoster::Default()->GetCatalog()->GetString(("Not enough free memory to finish the effect you requested. You may close other images and try again. " "Also shortening the depth of undo or disabling undo altogether helps in achieving more memory. " "If you have other applications running, closing them gives you more free memory. " "It is also a good idea to save your work at this point, because if the memory runs out completely " "saving might become impossible. I am very sorry about this inconvenience." ), "ImageView") | |||
1960 | "Also shortening the depth of undo or disabling undo altogether helps in achieving more memory. "\BLocaleRoster::Default()->GetCatalog()->GetString(("Not enough free memory to finish the effect you requested. You may close other images and try again. " "Also shortening the depth of undo or disabling undo altogether helps in achieving more memory. " "If you have other applications running, closing them gives you more free memory. " "It is also a good idea to save your work at this point, because if the memory runs out completely " "saving might become impossible. I am very sorry about this inconvenience." ), "ImageView") | |||
1961 | "If you have other applications running, closing them gives you more free memory. "\BLocaleRoster::Default()->GetCatalog()->GetString(("Not enough free memory to finish the effect you requested. You may close other images and try again. " "Also shortening the depth of undo or disabling undo altogether helps in achieving more memory. " "If you have other applications running, closing them gives you more free memory. " "It is also a good idea to save your work at this point, because if the memory runs out completely " "saving might become impossible. I am very sorry about this inconvenience." ), "ImageView") | |||
1962 | "It is also a good idea to save your work at this point, because if the memory runs out completely "\BLocaleRoster::Default()->GetCatalog()->GetString(("Not enough free memory to finish the effect you requested. You may close other images and try again. " "Also shortening the depth of undo or disabling undo altogether helps in achieving more memory. " "If you have other applications running, closing them gives you more free memory. " "It is also a good idea to save your work at this point, because if the memory runs out completely " "saving might become impossible. I am very sorry about this inconvenience." ), "ImageView") | |||
1963 | "saving might become impossible. I am very sorry about this inconvenience.")BLocaleRoster::Default()->GetCatalog()->GetString(("Not enough free memory to finish the effect you requested. You may close other images and try again. " "Also shortening the depth of undo or disabling undo altogether helps in achieving more memory. " "If you have other applications running, closing them gives you more free memory. " "It is also a good idea to save your work at this point, because if the memory runs out completely " "saving might become impossible. I am very sorry about this inconvenience." ), "ImageView"); | |||
1964 | break; | |||
1965 | ||||
1966 | default: | |||
1967 | text = "This alert should never show up"; | |||
1968 | break; | |||
1969 | } | |||
1970 | ||||
1971 | BAlert *alert_box = new BAlert("alert_box",text,B_TRANSLATE("OK")BLocaleRoster::Default()->GetCatalog()->GetString(("OK" ), "ImageView"),NULL__null,NULL__null,B_WIDTH_AS_USUAL,B_WARNING_ALERT); | |||
1972 | alert_box->Go(); | |||
1973 | ||||
1974 | ||||
1975 | return B_OK((int)0); | |||
1976 | } | |||
1977 | ||||
1978 | ||||
1979 | void ImageView::SetCursor() | |||
1980 | { | |||
1981 | BPoint point; | |||
1982 | uint32 buttons; | |||
1983 | BRegion region; | |||
1984 | ||||
1985 | if (LockLooper() == TRUE1) { | |||
1986 | GetClippingRegion(®ion); | |||
1987 | GetMouse(&point,&buttons); | |||
1988 | UnlockLooper(); | |||
1989 | } | |||
1990 | ||||
1991 | if (region.Contains(point)) { | |||
1992 | if (cursor_mode == NORMAL_CURSOR_MODE) { | |||
1993 | be_app->SetCursor(ToolManager::Instance().ReturnCursor()); | |||
1994 | } | |||
1995 | else if (cursor_mode == MANIPULATOR_CURSOR_MODE) { | |||
1996 | GUIManipulator *gui_manipulator = cast_as(fManipulator,GUIManipulator)(dynamic_cast<GUIManipulator*>(fManipulator)); | |||
1997 | if (gui_manipulator != NULL__null) { | |||
1998 | if (gui_manipulator->ManipulatorCursor() != NULL__null) | |||
1999 | be_app->SetCursor(gui_manipulator->ManipulatorCursor()); | |||
2000 | else | |||
2001 | be_app->SetCursor(B_HAND_CURSOR); | |||
2002 | } | |||
2003 | } | |||
2004 | else if (cursor_mode == BLOCKING_CURSOR_MODE) { | |||
2005 | be_app->SetCursor(HS_BLOCKING_CURSOR); | |||
2006 | } | |||
2007 | } | |||
2008 | else { | |||
2009 | be_app->SetCursor(B_HAND_CURSOR); | |||
2010 | } | |||
2011 | } | |||
2012 | ||||
2013 | ||||
2014 | void ImageView::SetDisplayMode(int32 new_display_mode) | |||
2015 | { | |||
2016 | if (current_display_mode != new_display_mode) { | |||
2017 | current_display_mode = new_display_mode; | |||
2018 | ||||
2019 | if (current_display_mode == DITHERED_8_BIT_DISPLAY_MODE) { | |||
2020 | if (the_image->RegisterDitheredUser(this) == B_ERROR(-1)) { | |||
2021 | current_display_mode = FULL_RGB_DISPLAY_MODE; | |||
2022 | } | |||
2023 | } | |||
2024 | else { | |||
2025 | the_image->UnregisterDitheredUser(this); | |||
2026 | } | |||
2027 | ||||
2028 | Invalidate(); | |||
2029 | } | |||
2030 | } | |||
2031 | ||||
2032 | ||||
2033 | void ImageView::SetReferencePoint(BPoint point,bool use) | |||
2034 | { | |||
2035 | reference_point = point; | |||
2036 | use_reference_point = use; | |||
2037 | } | |||
2038 | ||||
2039 | void ImageView::SetToolHelpString(const char *string) | |||
2040 | { | |||
2041 | if (LockLooper() == TRUE1) { | |||
2042 | ((PaintWindow*)Window())->SetHelpString(string,HS_TOOL_HELP_MESSAGE'TolM'); | |||
2043 | UnlockLooper(); | |||
2044 | } | |||
2045 | } | |||
2046 | ||||
2047 | ||||
2048 | void ImageView::SetProjectName(const char *name) | |||
2049 | { | |||
2050 | delete[] project_name; | |||
2051 | ||||
2052 | project_name = new char[strlen(name) + 1]; | |||
2053 | strcpy(project_name,name); | |||
2054 | ||||
2055 | setWindowTitle(); | |||
2056 | } | |||
2057 | ||||
2058 | ||||
2059 | void ImageView::SetImageName(const char *name) | |||
2060 | { | |||
2061 | delete[] image_name; | |||
2062 | ||||
2063 | image_name = new char[strlen(name) + 1]; | |||
2064 | strcpy(image_name,name); | |||
2065 | ||||
2066 | setWindowTitle(); | |||
2067 | } | |||
2068 | ||||
2069 | ||||
2070 | ||||
2071 | void | |||
2072 | ImageView::setWindowTitle() | |||
2073 | { | |||
2074 | BString title; | |||
2075 | if (true) { | |||
2076 | // Experimental style title | |||
2077 | BString pname = project_name; | |||
2078 | BString iname = image_name; | |||
2079 | ||||
2080 | BString pchanged = ""; | |||
2081 | BString ichanged = ""; | |||
2082 | ||||
2083 | if (project_name == NULL__null) | |||
2084 | pname = ""; | |||
2085 | ||||
2086 | if (project_changed > 0) | |||
2087 | pchanged = "(*) "; | |||
2088 | if (image_changed > 0) | |||
2089 | ichanged = "(*)"; | |||
2090 | ||||
2091 | title << pchanged << pname; | |||
2092 | if (iname != NULL__null) | |||
2093 | title << " | (" << iname << ")"; | |||
2094 | } | |||
2095 | ||||
2096 | if (LockLooper()) { | |||
2097 | Window()->SetTitle(title); | |||
2098 | UnlockLooper(); | |||
2099 | } | |||
2100 | } | |||
2101 | ||||
2102 | ||||
2103 | void ImageView::AddChange() | |||
2104 | { | |||
2105 | project_changed++; | |||
2106 | image_changed++; | |||
2107 | ||||
2108 | if ((project_changed == 1) || (image_changed == 1)) { | |||
2109 | setWindowTitle(); | |||
2110 | } | |||
2111 | } | |||
2112 | ||||
2113 | ||||
2114 | void ImageView::RemoveChange() | |||
2115 | { | |||
2116 | project_changed = max_c(0,project_changed-1)((0)>(project_changed-1)?(0):(project_changed-1)); | |||
2117 | image_changed = max_c(0,image_changed-1)((0)>(image_changed-1)?(0):(image_changed-1)); | |||
2118 | } | |||
2119 | ||||
2120 | ||||
2121 | void ImageView::ResetChangeStatistics(bool project, bool image) | |||
2122 | { | |||
2123 | if (project) | |||
2124 | project_changed = 0; | |||
2125 | if (image) | |||
2126 | image_changed = 0; | |||
2127 | ||||
2128 | setWindowTitle(); | |||
2129 | } | |||
2130 | ||||
2131 | ||||
2132 | bool ImageView::PostponeMessageAndFinishManipulator() | |||
2133 | { | |||
2134 | if (fManipulator) { | |||
2135 | BMessage message(HS_MANIPULATOR_FINISHED'MnFi'); | |||
2136 | message.AddBool("status", true); | |||
2137 | Window()->PostMessage(&message, this); | |||
2138 | ||||
2139 | manipulator_finishing_message = Window()->DetachCurrentMessage(); | |||
2140 | return true; | |||
2141 | } | |||
2142 | return false; | |||
2143 | } | |||
2144 | ||||
2145 | ||||
2146 | ||||
2147 | ||||
2148 | ||||
2149 | ||||
2150 | ||||
2151 | filter_result KeyFilterFunction(BMessage *message,BHandler **handler,BMessageFilter*) | |||
2152 | { | |||
2153 | // message->PrintToStream(); | |||
2154 | ImageView *view = dynamic_cast<ImageView*>(*handler); | |||
2155 | if (view != NULL__null) { | |||
2156 | if (acquire_sem_etc(view->mouse_mutex,1,B_RELATIVE_TIMEOUT,0) == B_OK((int)0)) { | |||
2157 | const char *bytes; | |||
2158 | if ((!(modifiers() & B_COMMAND_KEY)) && (!(modifiers() & B_CONTROL_KEY))) { | |||
2159 | if (message->FindString("bytes",&bytes) == B_OK((int)0)) { | |||
2160 | switch (bytes[0]) { | |||
2161 | case 'b': | |||
2162 | ToolManager::Instance().ChangeTool(BRUSH_TOOL); | |||
2163 | view->SetCursor(); | |||
2164 | break; | |||
2165 | ||||
2166 | case 'a': | |||
2167 | ToolManager::Instance().ChangeTool(AIR_BRUSH_TOOL); | |||
2168 | view->SetCursor(); | |||
2169 | break; | |||
2170 | ||||
2171 | case 'e': | |||
2172 | ToolManager::Instance().ChangeTool(ERASER_TOOL); | |||
2173 | view->SetCursor(); | |||
2174 | break; | |||
2175 | ||||
2176 | case 'f': | |||
2177 | ToolManager::Instance().ChangeTool(FREE_LINE_TOOL); | |||
2178 | view->SetCursor(); | |||
2179 | break; | |||
2180 | ||||
2181 | case 's': | |||
2182 | ToolManager::Instance().ChangeTool(SELECTOR_TOOL); | |||
2183 | view->SetCursor(); | |||
2184 | break; | |||
2185 | ||||
2186 | case 'r': | |||
2187 | ToolManager::Instance().ChangeTool(RECTANGLE_TOOL); | |||
2188 | view->SetCursor(); | |||
2189 | break; | |||
2190 | ||||
2191 | case 'l': | |||
2192 | ToolManager::Instance().ChangeTool(STRAIGHT_LINE_TOOL); | |||
2193 | view->SetCursor(); | |||
2194 | break; | |||
2195 | ||||
2196 | case 'h': | |||
2197 | ToolManager::Instance().ChangeTool(HAIRY_BRUSH_TOOL); | |||
2198 | view->SetCursor(); | |||
2199 | break; | |||
2200 | ||||
2201 | case 'u': | |||
2202 | ToolManager::Instance().ChangeTool(BLUR_TOOL); | |||
2203 | view->SetCursor(); | |||
2204 | break; | |||
2205 | ||||
2206 | case 'i': | |||
2207 | ToolManager::Instance().ChangeTool(FILL_TOOL); | |||
2208 | view->SetCursor(); | |||
2209 | break; | |||
2210 | ||||
2211 | case 't': | |||
2212 | ToolManager::Instance().ChangeTool(TEXT_TOOL); | |||
2213 | view->SetCursor(); | |||
2214 | break; | |||
2215 | ||||
2216 | case 'n': | |||
2217 | ToolManager::Instance().ChangeTool(TRANSPARENCY_TOOL); | |||
2218 | view->SetCursor(); | |||
2219 | break; | |||
2220 | ||||
2221 | case 'c': | |||
2222 | ToolManager::Instance().ChangeTool(COLOR_SELECTOR_TOOL); | |||
2223 | view->SetCursor(); | |||
2224 | break; | |||
2225 | ||||
2226 | case 'p': | |||
2227 | ToolManager::Instance().ChangeTool(ELLIPSE_TOOL); | |||
2228 | view->SetCursor(); | |||
2229 | break; | |||
2230 | } | |||
2231 | } | |||
2232 | } | |||
2233 | ||||
2234 | release_sem(view->mouse_mutex); | |||
2235 | } | |||
2236 | } | |||
2237 | return B_DISPATCH_MESSAGE; | |||
2238 | } |