File: | home/HaikuArchives/ArtPaint/artpaint/tools/StraightLineTool.cpp |
Warning: | line 193, column 19 Called C++ object pointer is null |
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 "StraightLineTool.h" | |||
14 | ||||
15 | #include "BitmapDrawer.h" | |||
16 | #include "Cursors.h" | |||
17 | #include "HSPolygon.h" | |||
18 | #include "Image.h" | |||
19 | #include "ImageView.h" | |||
20 | #include "NumberSliderControl.h" | |||
21 | #include "PaintApplication.h" | |||
22 | #include "Selection.h" | |||
23 | #include "ToolScript.h" | |||
24 | #include "UtilityClasses.h" | |||
25 | ||||
26 | ||||
27 | #include <Catalog.h> | |||
28 | #include <CheckBox.h> | |||
29 | #include <GridLayoutBuilder.h> | |||
30 | #include <GroupLayoutBuilder.h> | |||
31 | #include <SeparatorView.h> | |||
32 | #include <Window.h> | |||
33 | ||||
34 | ||||
35 | #include <math.h> | |||
36 | #include <stdio.h> | |||
37 | ||||
38 | ||||
39 | #undef B_TRANSLATION_CONTEXT"Tools" | |||
40 | #define B_TRANSLATION_CONTEXT"Tools" "Tools" | |||
41 | ||||
42 | ||||
43 | using ArtPaint::Interface::NumberSliderControl; | |||
44 | ||||
45 | ||||
46 | StraightLineTool::StraightLineTool() | |||
47 | : DrawingTool(B_TRANSLATE("Straight line tool")BLocaleRoster::Default()->GetCatalog()->GetString(("Straight line tool" ), "Tools"), | |||
48 | STRAIGHT_LINE_TOOL) | |||
49 | { | |||
50 | fOptions = SIZE_OPTION | ANTI_ALIASING_LEVEL_OPTION | MODE_OPTION; | |||
51 | fOptionsCount = 3; | |||
52 | ||||
53 | SetOption(SIZE_OPTION, 1); | |||
54 | SetOption(MODE_OPTION, B_CONTROL_ON); | |||
55 | SetOption(ANTI_ALIASING_LEVEL_OPTION, B_CONTROL_OFF); | |||
56 | } | |||
57 | ||||
58 | ||||
59 | StraightLineTool::~StraightLineTool() | |||
60 | { | |||
61 | } | |||
62 | ||||
63 | ||||
64 | ToolScript* | |||
65 | StraightLineTool::UseTool(ImageView* view, uint32 buttons, BPoint point, | |||
66 | BPoint view_point) | |||
67 | { | |||
68 | // In this function we calculate the line as a polygon. We make the polygon | |||
69 | // by first making a horizontal rectangle of appropriate size and the | |||
70 | // rotating around the starting-point by proper angle. | |||
71 | ||||
72 | // Wait for the last_updated_region to become empty | |||
73 | while (LastUpdatedRect().IsValid()) | |||
| ||||
74 | snooze(50000); | |||
75 | ||||
76 | BWindow *window = view->Window(); | |||
77 | drawing_mode old_mode; | |||
78 | BBitmap *bitmap = view->ReturnImage()->ReturnActiveBitmap(); | |||
79 | // BView *bitmap_view = view->getBufferView(); | |||
80 | ||||
81 | Selection *selection = view->GetSelection(); | |||
82 | ||||
83 | if (window != NULL__null) { | |||
84 | ToolScript* the_script = new ToolScript(Type(), fToolSettings, | |||
85 | ((PaintApplication*)be_app)->Color(true)); | |||
86 | ||||
87 | BitmapDrawer *drawer = new BitmapDrawer(bitmap); | |||
88 | ||||
89 | BPoint original_point,original_view_point,prev_view_point; | |||
90 | BRect bitmap_rect,old_rect,new_rect; | |||
91 | HSPolygon *view_polygon = NULL__null; | |||
92 | BPoint point_list[4]; | |||
93 | ||||
94 | window->Lock(); | |||
95 | old_mode = view->DrawingMode(); | |||
96 | view->SetDrawingMode(B_OP_INVERT); | |||
97 | window->Unlock(); | |||
98 | original_point = point; | |||
99 | rgb_color c = ((PaintApplication*)be_app)->Color(true); | |||
100 | ||||
101 | prev_view_point = original_view_point = view_point; | |||
102 | bitmap_rect = BRect(point.x, point.y - | |||
103 | floor(((float)GetCurrentValue(SIZE_OPTION) - 1.0) / 2.0), point.x, | |||
104 | point.y + ceil(((float)GetCurrentValue(SIZE_OPTION) - 1.0) / 2.0)); | |||
105 | old_rect = new_rect = view->convertBitmapRectToView(bitmap_rect); | |||
106 | point_list[0] = new_rect.LeftTop(); | |||
107 | point_list[1] = new_rect.RightTop(); | |||
108 | point_list[2] = new_rect.RightBottom(); | |||
109 | point_list[3] = new_rect.LeftBottom(); | |||
110 | ||||
111 | window->Lock(); | |||
112 | if ((GetCurrentValue(SIZE_OPTION) > 2) && (fToolSettings.mode == B_CONTROL_OFF)) { | |||
113 | view_polygon = new HSPolygon(point_list,4); | |||
114 | BPolygon *bpoly = view_polygon->GetBPolygon(); | |||
115 | view->StrokePolygon(bpoly); | |||
116 | delete bpoly; | |||
117 | } | |||
118 | else | |||
119 | view->StrokeLine(original_view_point,view_point); | |||
120 | window->Unlock(); | |||
121 | ||||
122 | float angle = 0; | |||
123 | while (buttons) { | |||
124 | window->Lock(); | |||
125 | view->getCoords(&point,&buttons,&view_point); | |||
126 | if (modifiers() & B_LEFT_SHIFT_KEY) { | |||
127 | // Make the new point be so that the angle is a multiple of 45°. | |||
128 | float x_diff,y_diff; | |||
129 | x_diff = fabs(original_point.x-point.x); | |||
130 | y_diff = fabs(original_point.y-point.y); | |||
131 | ||||
132 | if (x_diff < y_diff) { | |||
133 | if (x_diff < y_diff/2) | |||
134 | x_diff = 0; | |||
135 | else | |||
136 | x_diff = y_diff; | |||
137 | } | |||
138 | else { | |||
139 | if (y_diff < x_diff/2) | |||
140 | y_diff = 0; | |||
141 | else | |||
142 | y_diff = x_diff; | |||
143 | } | |||
144 | ||||
145 | float signed_x_diff = (point.x-original_point.x); | |||
146 | float signed_y_diff = (point.y-original_point.y); | |||
147 | ||||
148 | if (signed_x_diff != 0) | |||
149 | point.x = original_point.x + x_diff * signed_x_diff/fabs(signed_x_diff); | |||
150 | ||||
151 | if (signed_y_diff != 0) | |||
152 | point.y = original_point.y + y_diff * signed_y_diff/fabs(signed_y_diff); | |||
153 | ||||
154 | x_diff = fabs(original_view_point.x-view_point.x); | |||
155 | y_diff = fabs(original_view_point.y-view_point.y); | |||
156 | ||||
157 | if (x_diff < y_diff) { | |||
158 | if (x_diff < y_diff/2) | |||
159 | x_diff = 0; | |||
160 | else | |||
161 | x_diff = y_diff; | |||
162 | } | |||
163 | else { | |||
164 | if (y_diff < x_diff/2) | |||
165 | y_diff = 0; | |||
166 | else | |||
167 | y_diff = x_diff; | |||
168 | } | |||
169 | ||||
170 | ||||
171 | signed_x_diff = (view_point.x-original_view_point.x); | |||
172 | signed_y_diff = (view_point.y-original_view_point.y); | |||
173 | if (signed_x_diff != 0) { | |||
174 | view_point.x = original_view_point.x + | |||
175 | x_diff * signed_x_diff / fabs(signed_x_diff); | |||
176 | } | |||
177 | ||||
178 | if (signed_y_diff != 0) { | |||
179 | view_point.y = original_view_point.y + | |||
180 | y_diff * signed_y_diff / fabs(signed_y_diff); | |||
181 | } | |||
182 | } | |||
183 | ||||
184 | bitmap_rect = BRect(original_point.x, | |||
185 | original_point.y - floor(((float)GetCurrentValue(SIZE_OPTION) - 1.0) / 2.0), | |||
186 | original_point.x + sqrt(pow(original_point.x - point.x, 2) + | |||
187 | pow(original_point.y - point.y, 2)), original_point.y + | |||
188 | ceil(((float)GetCurrentValue(SIZE_OPTION) - 1.0) / 2.0)); | |||
189 | ||||
190 | new_rect = view->convertBitmapRectToView(bitmap_rect); | |||
191 | if (old_rect != new_rect) { | |||
192 | if ((GetCurrentValue(SIZE_OPTION) > 2) && (fToolSettings.mode == B_CONTROL_OFF)) { | |||
193 | BRect bbox = view_polygon->BoundingBox(); | |||
| ||||
194 | view->Draw(bbox); | |||
195 | point_list[0] = new_rect.LeftTop(); | |||
196 | point_list[1] = new_rect.RightTop(); | |||
197 | point_list[2] = new_rect.RightBottom(); | |||
198 | point_list[3] = new_rect.LeftBottom(); | |||
199 | view_polygon = new HSPolygon(point_list,4); | |||
200 | angle = atan2((view_point.y-original_view_point.y), | |||
201 | (view_point.x - original_view_point.x)) * 180 / M_PI3.14159265358979323846; | |||
202 | view_polygon->Rotate(original_view_point,angle); | |||
203 | BPolygon *bpoly = view_polygon->GetBPolygon(); | |||
204 | view->StrokePolygon(bpoly); | |||
205 | delete bpoly; | |||
206 | } | |||
207 | else { | |||
208 | float left = min_c(original_view_point.x, prev_view_point.x)((original_view_point.x)>(prev_view_point.x)?(prev_view_point .x):(original_view_point.x)); | |||
209 | float top = min_c(original_view_point.y, prev_view_point.y)((original_view_point.y)>(prev_view_point.y)?(prev_view_point .y):(original_view_point.y)); | |||
210 | float right = max_c(original_view_point.x, prev_view_point.x)((original_view_point.x)>(prev_view_point.x)?(original_view_point .x):(prev_view_point.x)); | |||
211 | float bottom = max_c(original_view_point.y, prev_view_point.y)((original_view_point.y)>(prev_view_point.y)?(original_view_point .y):(prev_view_point.y)); | |||
212 | BRect bbox(left, top, right, bottom); | |||
213 | view->Draw(bbox); | |||
214 | view->StrokeLine(original_view_point,view_point); | |||
215 | angle = atan2((view_point.y-original_view_point.y), | |||
216 | (view_point.x - original_view_point.x)) * 180 / M_PI3.14159265358979323846; | |||
217 | prev_view_point = view_point; | |||
218 | } | |||
219 | old_rect = new_rect; | |||
220 | } | |||
221 | window->Unlock(); | |||
222 | snooze(20 * 1000); | |||
223 | } | |||
224 | int32 size = GetCurrentValue(SIZE_OPTION); | |||
225 | bool draw_line = true; | |||
226 | new_rect = old_rect; | |||
227 | if (fToolSettings.mode == B_CONTROL_ON) { // Adjust the width of the line. | |||
228 | bool continue_adjusting_width = true; | |||
229 | BPoint p1 = original_point; | |||
230 | BPoint width_point; | |||
231 | view_polygon = new HSPolygon(NULL__null,0); | |||
232 | BRect orig_rect = bitmap_rect; | |||
233 | orig_rect.bottom = orig_rect.top = original_point.y; | |||
234 | ||||
235 | size = 0; | |||
236 | ||||
237 | while (continue_adjusting_width) { | |||
238 | if (is_clicks_data_valid) { | |||
239 | continue_adjusting_width = false; | |||
240 | is_clicks_data_valid = false; | |||
241 | } | |||
242 | else if (is_keys_data_valid) { | |||
243 | if (last_key_event_bytes[0] == B_ESCAPE) { | |||
244 | continue_adjusting_width = false; | |||
245 | draw_line = false; | |||
246 | } | |||
247 | is_keys_data_valid = false; | |||
248 | } | |||
249 | else { | |||
250 | if (view->LockLooper()) { | |||
251 | new_rect = orig_rect; | |||
252 | new_rect.bottom += size/2; | |||
253 | new_rect.top -= size/2; | |||
254 | new_rect = view->convertBitmapRectToView(new_rect); | |||
255 | if (new_rect != old_rect) { | |||
256 | if (size > 0) { | |||
257 | BRect bbox = view_polygon->BoundingBox(); | |||
258 | view->Draw(bbox); | |||
259 | point_list[0] = new_rect.LeftTop(); | |||
260 | point_list[1] = new_rect.RightTop(); | |||
261 | point_list[2] = new_rect.RightBottom(); | |||
262 | point_list[3] = new_rect.LeftBottom(); | |||
263 | view_polygon = new HSPolygon(point_list,4); | |||
264 | view_polygon->Rotate(original_view_point,angle); | |||
265 | BPolygon* bpoly = view_polygon->GetBPolygon(); | |||
266 | view->StrokePolygon(bpoly); | |||
267 | delete bpoly; | |||
268 | } | |||
269 | old_rect = new_rect; | |||
270 | } | |||
271 | view->getCoords(&width_point,&buttons); | |||
272 | view->UnlockLooper(); | |||
273 | width_point = width_point-p1; | |||
274 | BPoint spare = width_point; | |||
275 | width_point.x = cos(-angle / 180 * M_PI3.14159265358979323846) * spare.x - | |||
276 | sin(-angle / 180 * M_PI3.14159265358979323846) * spare.y; | |||
277 | width_point.y = sin(-angle / 180 * M_PI3.14159265358979323846) * spare.x + | |||
278 | cos(-angle / 180 * M_PI3.14159265358979323846) * spare.y; | |||
279 | size = (int32)(2 * fabs(width_point.y)); | |||
280 | } | |||
281 | snooze(20 * 1000); | |||
282 | } | |||
283 | } | |||
284 | } | |||
285 | delete view_polygon; | |||
286 | ||||
287 | bool anti_alias = true; | |||
288 | if (GetCurrentValue(ANTI_ALIASING_LEVEL_OPTION) == B_CONTROL_OFF) | |||
289 | anti_alias = false; | |||
290 | ||||
291 | if (size > 1) | |||
292 | drawer->DrawLine(original_point,point,RGBColorToBGRA(c),size,anti_alias,selection); | |||
293 | else | |||
294 | drawer->DrawHairLine(original_point,point,RGBColorToBGRA(c),anti_alias,selection); | |||
295 | ||||
296 | BRect updated_rect = MakeRectFromPoints(original_point, point); | |||
297 | ||||
298 | // This extension might actually be too little. | |||
299 | updated_rect.left -= size/2; | |||
300 | updated_rect.top -= size/2; | |||
301 | updated_rect.right += size/2; | |||
302 | updated_rect.bottom += size/2; | |||
303 | ||||
304 | SetLastUpdatedRect(updated_rect); | |||
305 | window->Lock(); | |||
306 | view->SetDrawingMode(old_mode); | |||
307 | view->UpdateImage(updated_rect); | |||
308 | view->Sync(); | |||
309 | window->Unlock(); | |||
310 | ||||
311 | delete drawer; | |||
312 | ||||
313 | the_script->AddPoint(original_point); | |||
314 | the_script->AddPoint(point); | |||
315 | return the_script; | |||
316 | } | |||
317 | ||||
318 | return NULL__null; | |||
319 | } | |||
320 | ||||
321 | ||||
322 | int32 | |||
323 | StraightLineTool::UseToolWithScript(ToolScript*,BBitmap*) | |||
324 | { | |||
325 | return B_OK((int)0); | |||
326 | } | |||
327 | ||||
328 | ||||
329 | BView* | |||
330 | StraightLineTool::ConfigView() | |||
331 | { | |||
332 | return new StraightLineToolConfigView(this); | |||
333 | } | |||
334 | ||||
335 | ||||
336 | const void* | |||
337 | StraightLineTool::ToolCursor() const | |||
338 | { | |||
339 | return HS_LINE_CURSOR; | |||
340 | } | |||
341 | ||||
342 | ||||
343 | const char* | |||
344 | StraightLineTool::HelpString(bool isInUse) const | |||
345 | { | |||
346 | return (isInUse | |||
347 | ? B_TRANSLATE("Drawing a straight line.")BLocaleRoster::Default()->GetCatalog()->GetString(("Drawing a straight line." ), "Tools") | |||
348 | : B_TRANSLATE("Click to draw a straight line.")BLocaleRoster::Default()->GetCatalog()->GetString(("Click to draw a straight line." ), "Tools")); | |||
349 | } | |||
350 | ||||
351 | ||||
352 | // #pragma mark -- StraightLineToolConfigView | |||
353 | ||||
354 | ||||
355 | StraightLineToolConfigView::StraightLineToolConfigView(DrawingTool* tool) | |||
356 | : DrawingToolConfigView(tool) | |||
357 | { | |||
358 | if (BLayout* layout = GetLayout()) { | |||
359 | BMessage* message = new BMessage(OPTION_CHANGED); | |||
360 | message->AddInt32("option", SIZE_OPTION); | |||
361 | message->AddInt32("value", tool->GetCurrentValue(SIZE_OPTION)); | |||
362 | ||||
363 | fLineSize = new NumberSliderControl( | |||
364 | B_TRANSLATE("Width:")BLocaleRoster::Default()->GetCatalog()->GetString(("Width:" ), "Tools"), | |||
365 | "1", message, 1, 100, false); | |||
366 | ||||
367 | message = new BMessage(OPTION_CHANGED); | |||
368 | message->AddInt32("option", ANTI_ALIASING_LEVEL_OPTION); | |||
369 | message->AddInt32("value", 0x00000000); | |||
370 | ||||
371 | fAntiAliasing = | |||
372 | new BCheckBox(B_TRANSLATE("Enable antialiasing")BLocaleRoster::Default()->GetCatalog()->GetString(("Enable antialiasing" ), "Tools"), | |||
373 | message); | |||
374 | if (tool->GetCurrentValue(ANTI_ALIASING_LEVEL_OPTION) != B_CONTROL_OFF) | |||
375 | fAntiAliasing->SetValue(B_CONTROL_ON); | |||
376 | ||||
377 | message = new BMessage(OPTION_CHANGED); | |||
378 | message->AddInt32("option", MODE_OPTION); | |||
379 | message->AddInt32("value", 0x00000000); | |||
380 | ||||
381 | fAdjustableWidth = | |||
382 | new BCheckBox(B_TRANSLATE("Adjustable width")BLocaleRoster::Default()->GetCatalog()->GetString(("Adjustable width" ), "Tools"), | |||
383 | message); | |||
384 | if (tool->GetCurrentValue(MODE_OPTION) != B_CONTROL_OFF) | |||
385 | fAdjustableWidth->SetValue(B_CONTROL_ON); | |||
386 | ||||
387 | BGridLayout* lineSizeLayout = LayoutSliderGrid(fLineSize); | |||
388 | ||||
389 | layout->AddView(BGroupLayoutBuilder(B_VERTICAL, kWidgetSpacing) | |||
390 | .Add(lineSizeLayout) | |||
391 | .AddStrut(kWidgetSpacing) | |||
392 | .Add(SeparatorView(B_TRANSLATE("Options")BLocaleRoster::Default()->GetCatalog()->GetString(("Options" ), "Tools"))) | |||
393 | .AddGroup(B_VERTICAL, kWidgetSpacing) | |||
394 | .Add(fAdjustableWidth) | |||
395 | .Add(fAntiAliasing) | |||
396 | .SetInsets(kWidgetInset, 0.0, 0.0, 0.0) | |||
397 | .End() | |||
398 | .TopView() | |||
399 | ); | |||
400 | } | |||
401 | } | |||
402 | ||||
403 | ||||
404 | void | |||
405 | StraightLineToolConfigView::AttachedToWindow() | |||
406 | { | |||
407 | DrawingToolConfigView::AttachedToWindow(); | |||
408 | ||||
409 | fLineSize->SetTarget(this); | |||
410 | fAntiAliasing->SetTarget(this); | |||
411 | fAdjustableWidth->SetTarget(this); | |||
412 | } |