File: | home/HaikuArchives/ArtPaint/artpaint/tools/FreeLineTool.cpp |
Warning: | line 76, column 10 Potential leak of memory pointed to by 'the_script' |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* | |||
2 | * Copyright 2003, Heikki Suhonen | |||
3 | * Copyright 2009, Karsten Heimrich | |||
4 | * Distributed under the terms of the MIT License. | |||
5 | * | |||
6 | * Authors: | |||
7 | * Heikki Suhonen <heikki.suhonen@gmail.com> | |||
8 | * Karsten Heimrich <host.haiku@gmx.de> | |||
9 | * Dale Cieslak <dcieslak@yahoo.com> | |||
10 | * | |||
11 | */ | |||
12 | ||||
13 | #include "FreeLineTool.h" | |||
14 | ||||
15 | #include "BitmapDrawer.h" | |||
16 | #include "BitmapUtilities.h" | |||
17 | #include "Cursors.h" | |||
18 | #include "CoordinateQueue.h" | |||
19 | #include "Image.h" | |||
20 | #include "ImageView.h" | |||
21 | #include "NumberSliderControl.h" | |||
22 | #include "PaintApplication.h" | |||
23 | #include "PixelOperations.h" | |||
24 | #include "ToolScript.h" | |||
25 | #include "UtilityClasses.h" | |||
26 | ||||
27 | ||||
28 | #include <Catalog.h> | |||
29 | #include <GridLayoutBuilder.h> | |||
30 | #include <Layout.h> | |||
31 | #include <Window.h> | |||
32 | ||||
33 | ||||
34 | #undef B_TRANSLATION_CONTEXT"Tools" | |||
35 | #define B_TRANSLATION_CONTEXT"Tools" "Tools" | |||
36 | ||||
37 | ||||
38 | using ArtPaint::Interface::NumberSliderControl; | |||
39 | ||||
40 | ||||
41 | FreeLineTool::FreeLineTool() | |||
42 | : DrawingTool(B_TRANSLATE("Freehand line tool")BLocaleRoster::Default()->GetCatalog()->GetString(("Freehand line tool" ), "Tools"), | |||
43 | FREE_LINE_TOOL) | |||
44 | { | |||
45 | fOptions = SIZE_OPTION; | |||
46 | fOptionsCount = 1; | |||
47 | ||||
48 | SetOption(SIZE_OPTION, 1); | |||
49 | } | |||
50 | ||||
51 | ||||
52 | FreeLineTool::~FreeLineTool() | |||
53 | { | |||
54 | } | |||
55 | ||||
56 | ||||
57 | ToolScript* | |||
58 | FreeLineTool::UseTool(ImageView* view, uint32 buttons, BPoint point, BPoint) | |||
59 | { | |||
60 | // Wait for the last_updated_region to become empty | |||
61 | while (LastUpdatedRect().IsValid()) | |||
| ||||
62 | snooze(50000); | |||
63 | ||||
64 | coordinate_queue = new CoordinateQueue(); | |||
65 | image_view = view; | |||
66 | thread_id coordinate_reader = spawn_thread(CoordinateReader, | |||
67 | "read coordinates", B_NORMAL_PRIORITY10, this); | |||
68 | resume_thread(coordinate_reader); | |||
69 | reading_coordinates = true; | |||
70 | ToolScript *the_script = new ToolScript(Type(), fToolSettings, | |||
71 | ((PaintApplication*)be_app)->Color(true)); | |||
72 | ||||
73 | BBitmap* buffer = view->ReturnImage()->ReturnActiveBitmap(); | |||
74 | BBitmap* srcBuffer = new (std::nothrow) BBitmap(buffer); | |||
75 | if (srcBuffer == NULL__null) | |||
76 | return NULL__null; | |||
| ||||
77 | BBitmap* tmpBuffer = new (std::nothrow) BBitmap(buffer); | |||
78 | if (tmpBuffer == NULL__null) { | |||
79 | delete srcBuffer; | |||
80 | return NULL__null; | |||
81 | } | |||
82 | union color_conversion clear_color; | |||
83 | clear_color.word = 0xFFFFFFFF; | |||
84 | clear_color.bytes[3] = 0x01; | |||
85 | ||||
86 | BitmapUtilities::ClearBitmap(tmpBuffer, clear_color.word); | |||
87 | ||||
88 | Selection *selection = view->GetSelection(); | |||
89 | // BView *buffer_view = view->getBufferView(); | |||
90 | BitmapDrawer *drawer = new BitmapDrawer(tmpBuffer); | |||
91 | rgb_color new_color; | |||
92 | uint32 new_color_bgra; | |||
93 | // int32 original_mouse_speed; | |||
94 | // get_mouse_speed(&original_mouse_speed); | |||
95 | ||||
96 | if (buffer == NULL__null) { | |||
97 | delete the_script; | |||
98 | delete srcBuffer; | |||
99 | delete tmpBuffer; | |||
100 | ||||
101 | return NULL__null; | |||
102 | } | |||
103 | BPoint prev_point; | |||
104 | ||||
105 | prev_point = point; | |||
106 | BRect updated_rect; | |||
107 | status_t status_of_read; | |||
108 | int diameter = fToolSettings.size; | |||
109 | if ((diameter%2) == 0) | |||
110 | diameter++; | |||
111 | ||||
112 | new_color = ((PaintApplication*)be_app)->Color(true); | |||
113 | new_color_bgra = RGBColorToBGRA(new_color); | |||
114 | if (diameter != 1) | |||
115 | drawer->DrawCircle(prev_point, diameter / 2, new_color_bgra, | |||
116 | true, false, selection, NULL__null); | |||
117 | else | |||
118 | drawer->DrawHairLine(prev_point, point, new_color_bgra, | |||
119 | false, selection, NULL__null); | |||
120 | ||||
121 | // This makes sure that the view is updated even if just one point is drawn | |||
122 | updated_rect.left = min_c(point.x-diameter/2,prev_point.x-diameter/2)((point.x-diameter/2)>(prev_point.x-diameter/2)?(prev_point .x-diameter/2):(point.x-diameter/2)); | |||
123 | updated_rect.top = min_c(point.y-diameter/2,prev_point.y-diameter/2)((point.y-diameter/2)>(prev_point.y-diameter/2)?(prev_point .y-diameter/2):(point.y-diameter/2)); | |||
124 | updated_rect.right = max_c(point.x+diameter/2,prev_point.x+diameter/2)((point.x+diameter/2)>(prev_point.x+diameter/2)?(point.x+diameter /2):(prev_point.x+diameter/2)); | |||
125 | updated_rect.bottom = max_c(point.y+diameter/2,prev_point.y+diameter/2)((point.y+diameter/2)>(prev_point.y+diameter/2)?(point.y+diameter /2):(prev_point.y+diameter/2)); | |||
126 | ||||
127 | // We should do the composite picture and re-draw the window in | |||
128 | // a separate thread. | |||
129 | view->ReturnImage()->Render(updated_rect); | |||
130 | view->Window()->Lock(); | |||
131 | BitmapUtilities::CompositeBitmapOnSource(buffer, srcBuffer, | |||
132 | tmpBuffer, updated_rect); | |||
133 | // We have to use Draw, because Invalidate causes flickering by erasing | |||
134 | // the area before calling Draw. | |||
135 | view->Draw(view->convertBitmapRectToView(updated_rect)); | |||
136 | view->UpdateImage(updated_rect); | |||
137 | view->Sync(); | |||
138 | view->Window()->Unlock(); | |||
139 | ||||
140 | SetLastUpdatedRect(updated_rect); | |||
141 | the_script->AddPoint(point); | |||
142 | while (((status_of_read = coordinate_queue->Get(point)) == B_OK((int)0)) | |||
143 | || (reading_coordinates == true)) { | |||
144 | if ( (status_of_read == B_OK((int)0)) && (prev_point != point) ) { | |||
145 | the_script->AddPoint(point); | |||
146 | // if (modifiers() & B_LEFT_CONTROL_KEY) { | |||
147 | // set_mouse_speed(0); | |||
148 | // } | |||
149 | // else { | |||
150 | // set_mouse_speed(original_mouse_speed); | |||
151 | // } | |||
152 | // first set the color | |||
153 | new_color = ((PaintApplication*)be_app)->Color(true); | |||
154 | new_color_bgra = RGBColorToBGRA(new_color); | |||
155 | ||||
156 | diameter = fToolSettings.size; | |||
157 | if ((diameter%2) == 0) | |||
158 | diameter++; | |||
159 | ||||
160 | if (diameter != 1) { | |||
161 | drawer->DrawCircle(point,diameter / 2, new_color_bgra, | |||
162 | true, false, selection, NULL__null); | |||
163 | drawer->DrawLine(prev_point,point, new_color_bgra, diameter, | |||
164 | false, selection, NULL__null); | |||
165 | } | |||
166 | else | |||
167 | drawer->DrawHairLine(prev_point, point, new_color_bgra, | |||
168 | false, selection); | |||
169 | ||||
170 | updated_rect.left = min_c(point.x-diameter/2-1,prev_point.x-diameter/2-1)((point.x-diameter/2-1)>(prev_point.x-diameter/2-1)?(prev_point .x-diameter/2-1):(point.x-diameter/2-1)); | |||
171 | updated_rect.top = min_c(point.y-diameter/2-1,prev_point.y-diameter/2-1)((point.y-diameter/2-1)>(prev_point.y-diameter/2-1)?(prev_point .y-diameter/2-1):(point.y-diameter/2-1)); | |||
172 | updated_rect.right = max_c(point.x+diameter/2+1,prev_point.x+diameter/2+1)((point.x+diameter/2+1)>(prev_point.x+diameter/2+1)?(point .x+diameter/2+1):(prev_point.x+diameter/2+1)); | |||
173 | updated_rect.bottom = max_c(point.y+diameter/2+1,prev_point.y+diameter/2+1)((point.y+diameter/2+1)>(prev_point.y+diameter/2+1)?(point .y+diameter/2+1):(prev_point.y+diameter/2+1)); | |||
174 | ||||
175 | SetLastUpdatedRect(LastUpdatedRect() | updated_rect); | |||
176 | ||||
177 | // We should do the composite picture and re-draw the window in | |||
178 | // a separate thread. | |||
179 | view->Window()->Lock(); | |||
180 | BitmapUtilities::CompositeBitmapOnSource(buffer, srcBuffer, | |||
181 | tmpBuffer, updated_rect); | |||
182 | view->UpdateImage(updated_rect); | |||
183 | view->Sync(); | |||
184 | view->Window()->Unlock(); | |||
185 | prev_point = point; | |||
186 | } | |||
187 | else | |||
188 | snooze(20 * 1000); | |||
189 | } | |||
190 | ||||
191 | delete srcBuffer; | |||
192 | delete tmpBuffer; | |||
193 | ||||
194 | delete drawer; | |||
195 | delete coordinate_queue; | |||
196 | return the_script; | |||
197 | } | |||
198 | ||||
199 | ||||
200 | int32 | |||
201 | FreeLineTool::UseToolWithScript(ToolScript*,BBitmap*) | |||
202 | { | |||
203 | return B_OK((int)0); | |||
204 | } | |||
205 | ||||
206 | ||||
207 | BView* | |||
208 | FreeLineTool::ConfigView() | |||
209 | { | |||
210 | return new FreeLineToolConfigView(this); | |||
211 | } | |||
212 | ||||
213 | ||||
214 | const void* | |||
215 | FreeLineTool::ToolCursor() const | |||
216 | { | |||
217 | return HS_FREE_LINE_CURSOR; | |||
218 | } | |||
219 | ||||
220 | ||||
221 | const char* | |||
222 | FreeLineTool::HelpString(bool isInUse) const | |||
223 | { | |||
224 | return (isInUse | |||
225 | ? B_TRANSLATE("Drawing a freehand line.")BLocaleRoster::Default()->GetCatalog()->GetString(("Drawing a freehand line." ), "Tools") | |||
226 | : B_TRANSLATE("Click to draw a freehand line.")BLocaleRoster::Default()->GetCatalog()->GetString(("Click to draw a freehand line." ), "Tools")); | |||
227 | } | |||
228 | ||||
229 | ||||
230 | int32 | |||
231 | FreeLineTool::CoordinateReader(void *data) | |||
232 | { | |||
233 | FreeLineTool *this_pointer = (FreeLineTool*)data; | |||
234 | return this_pointer->read_coordinates(); | |||
235 | } | |||
236 | ||||
237 | ||||
238 | int32 | |||
239 | FreeLineTool::read_coordinates() | |||
240 | { | |||
241 | reading_coordinates = true; | |||
242 | uint32 buttons; | |||
243 | BPoint point,prev_point; | |||
244 | BPoint view_point; | |||
245 | image_view->Window()->Lock(); | |||
246 | image_view->getCoords(&point,&buttons,&view_point); | |||
247 | image_view->MovePenTo(view_point); | |||
248 | image_view->Window()->Unlock(); | |||
249 | prev_point = point + BPoint(1,1); | |||
250 | ||||
251 | while (buttons) { | |||
252 | image_view->Window()->Lock(); | |||
253 | if (point != prev_point) { | |||
254 | coordinate_queue->Put(point); | |||
255 | image_view->StrokeLine(view_point); | |||
256 | prev_point = point; | |||
257 | } | |||
258 | image_view->getCoords(&point,&buttons,&view_point); | |||
259 | image_view->Window()->Unlock(); | |||
260 | snooze(20 * 1000); | |||
261 | } | |||
262 | ||||
263 | reading_coordinates = false; | |||
264 | return B_OK((int)0); | |||
265 | } | |||
266 | ||||
267 | ||||
268 | // #pragma mark -- FreeLineToolConfigView | |||
269 | ||||
270 | ||||
271 | FreeLineToolConfigView::FreeLineToolConfigView(DrawingTool* tool) | |||
272 | : DrawingToolConfigView(tool) | |||
273 | { | |||
274 | if (BLayout* layout = GetLayout()) { | |||
275 | BMessage* message = new BMessage(OPTION_CHANGED); | |||
276 | message->AddInt32("option", SIZE_OPTION); | |||
277 | message->AddInt32("value", tool->GetCurrentValue(SIZE_OPTION)); | |||
278 | ||||
279 | fLineSize = | |||
280 | new NumberSliderControl(B_TRANSLATE("Width:")BLocaleRoster::Default()->GetCatalog()->GetString(("Width:" ), "Tools"), | |||
281 | "1", message, 1, 100, false); | |||
282 | ||||
283 | BGridLayout* lineSizeLayout = LayoutSliderGrid(fLineSize); | |||
284 | ||||
285 | layout->AddView(lineSizeLayout->View()); | |||
286 | } | |||
287 | } | |||
288 | ||||
289 | ||||
290 | void | |||
291 | FreeLineToolConfigView::AttachedToWindow() | |||
292 | { | |||
293 | DrawingToolConfigView::AttachedToWindow(); | |||
294 | ||||
295 | fLineSize->SetTarget(this); | |||
296 | } |