File: | home/HaikuArchives/ArtPaint/artpaint/tools/BrushEditor.cpp |
Warning: | line 474, column 8 Value stored to 'angle' during its initialization is never read |
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 "BrushEditor.h" |
14 | |
15 | #include "BrushStoreWindow.h" |
16 | #include "HSPolygon.h" |
17 | #include "FloatSliderControl.h" |
18 | #include "NumberSliderControl.h" |
19 | #include "UtilityClasses.h" |
20 | |
21 | |
22 | #include <Button.h> |
23 | #include <Catalog.h> |
24 | #include <CheckBox.h> |
25 | #include <GridLayoutBuilder.h> |
26 | #include <GroupLayout.h> |
27 | #include <GroupLayoutBuilder.h> |
28 | #include <RadioButton.h> |
29 | #include <SeparatorView.h> |
30 | |
31 | |
32 | #include <math.h> |
33 | |
34 | |
35 | #undef B_TRANSLATION_CONTEXT"Tools" |
36 | #define B_TRANSLATION_CONTEXT"Tools" "Tools" |
37 | |
38 | |
39 | enum { |
40 | kExtraEdge = 4, |
41 | kBrushAltered = 'kbal', |
42 | kBrushSizeChanged = 'kbsz', |
43 | kBrushRatioChanged = 'kbrc', |
44 | kBrushFadeChanged = 'kbfc', |
45 | kBrushShapeChanged = 'kbsc', |
46 | kBrushStoreRequest = 'kbsr', |
47 | kBrushResetRequest = 'kbrr', |
48 | kBrushAngleChanged = 'kbac', |
49 | }; |
50 | |
51 | |
52 | BrushEditor* BrushEditor::fBrushEditor = NULL__null; |
53 | using ArtPaint::Interface::NumberSliderControl; |
54 | |
55 | |
56 | BrushEditor::BrushEditor(Brush* brush) |
57 | : BBox(B_FANCY_BORDER, NULL__null) |
58 | , fBrush(brush) |
59 | , fBrushInfo(fBrush->GetInfo()) |
60 | { |
61 | float height = BRUSH_PREVIEW_HEIGHT64 - kExtraEdge; |
62 | float width = BRUSH_PREVIEW_WIDTH64 - kExtraEdge; |
63 | |
64 | fBrushView = new BrushView(BRect(kExtraEdge, kExtraEdge, width, height), |
65 | fBrush); |
66 | |
67 | BMessage* message = new BMessage(kBrushShapeChanged); |
68 | message->AddInt32("shape", HS_RECTANGULAR_BRUSH); |
69 | |
70 | fRectangle = new BRadioButton(B_TRANSLATE("Rectangle")BLocaleRoster::Default()->GetCatalog()->GetString(("Rectangle" ), "Tools"), |
71 | message); |
72 | |
73 | message = new BMessage(kBrushShapeChanged); |
74 | message->AddInt32("shape", HS_ELLIPTICAL_BRUSH); |
75 | |
76 | fEllipse = new BRadioButton(B_TRANSLATE("Ellipse")BLocaleRoster::Default()->GetCatalog()->GetString(("Ellipse" ), "Tools"), |
77 | message); |
78 | |
79 | fStoreBrush = new BButton(B_TRANSLATE("Store brush")BLocaleRoster::Default()->GetCatalog()->GetString(("Store brush" ), "Tools"), |
80 | new BMessage(kBrushStoreRequest)); |
81 | |
82 | fResetBrush = new BButton(B_TRANSLATE("Reset brush")BLocaleRoster::Default()->GetCatalog()->GetString(("Reset brush" ), "Tools"), |
83 | new BMessage(kBrushResetRequest)); |
84 | |
85 | message = new BMessage(kBrushSizeChanged); |
86 | message->AddInt32("value", int32(fBrushInfo.width)); |
87 | |
88 | fBrushSize = |
89 | new NumberSliderControl(B_TRANSLATE("Size:")BLocaleRoster::Default()->GetCatalog()->GetString(("Size:" ), "Tools"), "0", |
90 | message, 1, 500, false, true, B_NO_BORDER, B_TRIANGLE_THUMB, true); |
91 | |
92 | message = new BMessage(kBrushRatioChanged); |
93 | message->AddFloat("value", 0); |
94 | |
95 | fBrushRatio = |
96 | new FloatSliderControl(B_TRANSLATE("Aspect:")BLocaleRoster::Default()->GetCatalog()->GetString(("Aspect:" ), "Tools"), "0", |
97 | message, -10., 10., false); |
98 | |
99 | fBrushRatio->Slider()->SetHashMarks(B_HASH_MARKS_BOTTOM); |
100 | fBrushRatio->Slider()->SetHashMarkCount(5); |
101 | |
102 | message = new BMessage(kBrushAngleChanged); |
103 | message->AddInt32("value", int32(fBrushInfo.angle)); |
104 | |
105 | fBrushAngle = |
106 | new NumberSliderControl(B_TRANSLATE("Angle:")BLocaleRoster::Default()->GetCatalog()->GetString(("Angle:" ), "Tools"), "0", |
107 | message, -90, 90, false); |
108 | |
109 | fBrushAngle->Slider()->SetHashMarks(B_HASH_MARKS_BOTTOM); |
110 | fBrushAngle->Slider()->SetHashMarkCount(5); |
111 | |
112 | message = new BMessage(kBrushFadeChanged); |
113 | message->AddInt32("value", int32(fBrushInfo.hardness)); |
114 | |
115 | fBrushFade = |
116 | new NumberSliderControl(B_TRANSLATE("Hardness:")BLocaleRoster::Default()->GetCatalog()->GetString(("Hardness:" ), "Tools"), "0", |
117 | message, 0, 100, false); |
118 | |
119 | BSeparatorView* view = new BSeparatorView(B_HORIZONTAL, B_FANCY_BORDER); |
120 | view->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); |
121 | |
122 | BGridLayout* gridLayout = BGridLayoutBuilder(5.0, 5.0) |
123 | .Add(fBrushSize, 0, 0, 0, 0) |
124 | .Add(fBrushSize->LabelLayoutItem(), 0, 0) |
125 | .Add(fBrushSize->TextViewLayoutItem(), 1, 0) |
126 | .Add(fBrushSize->Slider(), 2, 0) |
127 | .Add(fBrushRatio, 0, 1, 0, 0) |
128 | .Add(fBrushRatio->LabelLayoutItem(), 0, 1) |
129 | .Add(fBrushRatio->TextViewLayoutItem(), 1, 1) |
130 | .Add(fBrushRatio->Slider(), 2, 1) |
131 | .Add(fBrushAngle, 0, 2, 0, 0) |
132 | .Add(fBrushAngle->LabelLayoutItem(), 0, 2) |
133 | .Add(fBrushAngle->TextViewLayoutItem(), 1, 2) |
134 | .Add(fBrushAngle->Slider(), 2, 2) |
135 | .Add(fBrushFade, 0, 3, 0, 0) |
136 | .Add(fBrushFade->LabelLayoutItem(), 0, 3) |
137 | .Add(fBrushFade->TextViewLayoutItem(), 1, 3) |
138 | .Add(fBrushFade->Slider(), 2, 3); |
139 | gridLayout->SetMaxColumnWidth(1, StringWidth("1000")); |
140 | gridLayout->SetMinColumnWidth(2, StringWidth("SLIDERSLIDERSLIDERSLIDER")); |
141 | |
142 | SetLayout(new BGroupLayout(B_VERTICAL)); |
143 | AddChild(BGroupLayoutBuilder(B_VERTICAL, 5.0) |
144 | .AddGroup(B_HORIZONTAL, 5.0) |
145 | .AddStrut(5.0) |
146 | .Add(fBrushView) |
147 | .AddGroup(B_VERTICAL, 5.0) |
148 | .Add(fEllipse) |
149 | .Add(fRectangle) |
150 | .AddGlue() |
151 | .End() |
152 | .AddGlue() |
153 | .End() |
154 | .AddStrut(1.0) |
155 | .Add(view) |
156 | .AddStrut(1.0) |
157 | .Add(gridLayout->View()) |
158 | .AddStrut(1.0) |
159 | .AddGroup(B_HORIZONTAL) |
160 | .Add(fResetBrush) |
161 | .AddGlue() |
162 | .Add(fStoreBrush) |
163 | .End() |
164 | ); |
165 | } |
166 | |
167 | |
168 | BrushEditor::~BrushEditor() |
169 | { |
170 | fBrushEditor = NULL__null; |
171 | } |
172 | |
173 | |
174 | BView* |
175 | BrushEditor::CreateBrushEditor(Brush* brush) |
176 | { |
177 | if (fBrushEditor) |
178 | return NULL__null; |
179 | |
180 | fBrushEditor = new BrushEditor(brush); |
181 | return fBrushEditor; |
182 | } |
183 | |
184 | |
185 | void |
186 | BrushEditor::BrushModified() |
187 | { |
188 | if (fBrushEditor) { |
189 | BWindow* window = fBrushEditor->Window(); |
190 | |
191 | bool locked = false; |
192 | if (window && window->Lock()) |
193 | locked = true; |
194 | |
195 | fBrushEditor->fBrushView->BrushModified(); |
196 | |
197 | if (window) |
198 | window->PostMessage(kBrushAltered, fBrushEditor); |
199 | |
200 | if (window && locked) |
201 | window->Unlock(); |
202 | } |
203 | } |
204 | |
205 | |
206 | void |
207 | BrushEditor::AttachedToWindow() |
208 | { |
209 | fBrushFade->SetTarget(this); |
210 | fBrushSize->SetTarget(this); |
211 | fBrushRatio->SetTarget(this); |
212 | fBrushAngle->SetTarget(this); |
213 | |
214 | fEllipse->SetTarget(this); |
215 | fRectangle->SetTarget(this); |
216 | fStoreBrush->SetTarget(this); |
217 | fResetBrush->SetTarget(this); |
218 | |
219 | if (fBrushInfo.shape == HS_RECTANGULAR_BRUSH) |
220 | fRectangle->SetValue(B_CONTROL_ON); |
221 | |
222 | if (fBrushInfo.shape == HS_ELLIPTICAL_BRUSH) |
223 | fEllipse->SetValue(B_CONTROL_ON); |
224 | } |
225 | |
226 | |
227 | void |
228 | BrushEditor::MessageReceived(BMessage* message) |
229 | { |
230 | switch (message->what) { |
231 | case kBrushSizeChanged: { |
232 | int32 value; |
233 | if (message->FindInt32("value", &value) == B_OK((int)0)) { |
234 | float ratio = fBrushRatio->Value(); |
235 | |
236 | float realRatio = 1.0 / (0.9 * fabs(ratio) + 1.); |
237 | |
238 | if (value < 0) { |
239 | fBrushInfo.width = max_c(value, 1)((value)>(1)?(value):(1)); |
240 | fBrushInfo.height = max_c(value / realRatio, 1)((value / realRatio)>(1)?(value / realRatio):(1)); |
241 | } else { |
242 | fBrushInfo.width = max_c(value / realRatio, 1)((value / realRatio)>(1)?(value / realRatio):(1)); |
243 | fBrushInfo.height = max_c(value, 1)((value)>(1)?(value):(1)); |
244 | } |
245 | |
246 | fBrush->ModifyBrush(fBrushInfo); |
247 | fBrushView->BrushModified(); |
248 | |
249 | bool final; |
250 | if (message->FindBool("final", &final) == B_OK((int)0) && final) |
251 | fBrush->CreateDiffBrushes(); |
252 | } |
253 | } break; |
254 | |
255 | case kBrushRatioChanged: { |
256 | float value; |
257 | if (message->FindFloat("value", &value) == B_OK((int)0)) { |
258 | float realRatio = 1.0 / (0.9 * fabs(value) + 1.); |
259 | |
260 | if (value < 0) { |
261 | fBrushInfo.width = max_c(fBrushSize->Value(), 1)((fBrushSize->Value())>(1)?(fBrushSize->Value()):(1) ); |
262 | fBrushInfo.height = max_c(fBrushSize->Value() / realRatio, 1)((fBrushSize->Value() / realRatio)>(1)?(fBrushSize-> Value() / realRatio):(1)); |
263 | } else { |
264 | fBrushInfo.width = max_c(fBrushSize->Value() / realRatio, 1)((fBrushSize->Value() / realRatio)>(1)?(fBrushSize-> Value() / realRatio):(1)); |
265 | fBrushInfo.height = max_c(fBrushSize->Value(), 1)((fBrushSize->Value())>(1)?(fBrushSize->Value()):(1) ); |
266 | } |
267 | |
268 | fBrush->ModifyBrush(fBrushInfo); |
269 | fBrushView->BrushModified(); |
270 | |
271 | bool final; |
272 | if (message->FindBool("final", &final) == B_OK((int)0) && final) |
273 | fBrush->CreateDiffBrushes(); |
274 | } |
275 | } break; |
276 | |
277 | case kBrushAngleChanged: { |
278 | int32 value; |
279 | if (message->FindInt32("value", &value) == B_OK((int)0)) { |
280 | fBrushInfo.angle = value; |
281 | fBrush->ModifyBrush(fBrushInfo); |
282 | fBrushView->BrushModified(); |
283 | |
284 | bool final; |
285 | if (message->FindBool("final", &final) == B_OK((int)0) && final) |
286 | fBrush->CreateDiffBrushes(); |
287 | } |
288 | } break; |
289 | |
290 | case kBrushFadeChanged: { |
291 | int32 value; |
292 | if (message->FindInt32("value",&value) == B_OK((int)0)) { |
293 | fBrushInfo.hardness = value; |
294 | fBrush->ModifyBrush(fBrushInfo); |
295 | fBrushView->BrushModified(); |
296 | |
297 | bool final; |
298 | if (message->FindBool("final", &final) == B_OK((int)0) && final) |
299 | fBrush->CreateDiffBrushes(); |
300 | } |
301 | } break; |
302 | |
303 | case kBrushShapeChanged: { |
304 | int32 value; |
305 | if (message->FindInt32("shape", &value) == B_OK((int)0)) { |
306 | fBrushInfo.shape = value; |
307 | fBrush->ModifyBrush(fBrushInfo); |
308 | fBrush->CreateDiffBrushes(); |
309 | fBrushView->BrushModified(); |
310 | } |
311 | } break; |
312 | |
313 | case kBrushAltered: { |
314 | // Here something has altered the brush and we should reflect it |
315 | // in our controls and such things. |
316 | fBrushInfo = fBrush->GetInfo(); |
317 | float ratio = (float)(fBrushInfo.width / fBrushInfo.height); |
318 | |
319 | if (ratio < 1.0) { |
320 | ratio = -1.0 / ratio; |
321 | fBrushSize->SetValue((int32)fBrushInfo.height); |
322 | } else |
323 | fBrushSize->SetValue((int32)fBrushInfo.width); |
324 | |
325 | if (ratio == 1.0) |
326 | ratio = 0; |
327 | |
328 | fBrushRatio->SetValue((int32)ratio); |
329 | |
330 | fBrushAngle->SetValue(int32(fBrushInfo.angle)); |
331 | fBrushFade->SetValue(int32(fBrushInfo.hardness)); |
332 | fBrushView->BrushModified(); |
333 | |
334 | if (fBrushInfo.shape == HS_RECTANGULAR_BRUSH) |
335 | fRectangle->SetValue(B_CONTROL_ON); |
336 | |
337 | if (fBrushInfo.shape == HS_ELLIPTICAL_BRUSH) |
338 | fEllipse->SetValue(B_CONTROL_ON); |
339 | } break; |
340 | |
341 | case kBrushStoreRequest: { |
342 | BrushStoreWindow::AddBrush(fBrush); |
343 | } break; |
344 | |
345 | case kBrushResetRequest: { |
346 | fBrushSize->SetValue(30); |
347 | fBrushRatio->SetValue(0); |
348 | fBrushAngle->SetValue(0); |
349 | fBrushFade->SetValue(2); |
350 | fRectangle->SetValue(B_CONTROL_OFF); |
351 | fEllipse->SetValue(B_CONTROL_ON); |
352 | |
353 | fBrushInfo.shape = HS_ELLIPTICAL_BRUSH; |
354 | fBrushInfo.width = 30; |
355 | fBrushInfo.height = 30; |
356 | fBrushInfo.angle = 0; |
357 | fBrushInfo.hardness = 2; |
358 | fBrush->ModifyBrush(fBrushInfo); |
359 | fBrush->CreateDiffBrushes(); |
360 | |
361 | fBrushView->BrushModified(); |
362 | } break; |
363 | |
364 | default: { |
365 | BView::MessageReceived(message); |
366 | } break; |
367 | } |
368 | } |
369 | |
370 | |
371 | // #pragma mark -- BrushView |
372 | |
373 | |
374 | BrushView::BrushView(BRect frame, Brush* brush) |
375 | : BView(frame, "brush view", B_FOLLOW_NONE0, B_WILL_DRAW) |
376 | , fDrawControls(false) |
377 | , fBrush(brush) |
378 | , fBrushPreview(NULL__null) |
379 | { |
380 | SetExplicitMinSize(BSize(frame.Width(), frame.Height())); |
381 | SetExplicitMaxSize(BSize(frame.Width(), frame.Height())); |
382 | |
383 | SetToolTip(B_TRANSLATE("Hold shift key to snap to 45° angles")BLocaleRoster::Default()->GetCatalog()->GetString(("Hold shift key to snap to 45° angles" ), "Tools")); |
384 | |
385 | frame.InsetBy(1.0, 1.0); |
386 | fBrushPreview = new BBitmap(BRect(0.0, 0.0, frame.Width() - 1.0, |
387 | frame.Height() - 1.0), B_RGBA32); |
388 | fBrush->PreviewBrush(fBrushPreview); |
389 | } |
390 | |
391 | |
392 | BrushView::~BrushView() |
393 | { |
394 | delete fBrushPreview; |
395 | } |
396 | |
397 | |
398 | void |
399 | BrushView::Draw(BRect) |
400 | { |
401 | DrawBitmap(fBrushPreview, BPoint(1.0, 1.0)); |
402 | |
403 | SetPenSize(1); |
404 | SetHighColor(0, 0, 0, 255); |
405 | StrokeRect(Bounds()); |
406 | |
407 | if (fDrawControls) { |
408 | float r1 = Bounds().Width()/2; |
409 | float r2 = Bounds().Height()/2; |
410 | BPoint point_list[12]; |
411 | point_list[0] = BPoint(0,r2-2); |
412 | point_list[1] = BPoint(0,0); |
413 | point_list[2] = BPoint(-r1*.5,0); |
414 | point_list[3] = BPoint(0,0); |
415 | point_list[4] = BPoint(0,-r2+7); |
416 | point_list[5] = BPoint(-2,-r2+7); |
417 | point_list[6] = BPoint(0,-r2+2); |
418 | point_list[7] = BPoint(2,-r2+7); |
419 | point_list[8] = BPoint(0,-r2+7); |
420 | point_list[9] = BPoint(0,0); |
421 | point_list[10] = BPoint(r1*.5,0); |
422 | point_list[11] = BPoint(0,0); |
423 | |
424 | HSPolygon poly(point_list, 12); |
425 | poly.Rotate(BPoint(0, 0), fBrush->GetInfo().angle); |
426 | poly.TranslateBy(int32(r1 - 1), int32(r2 - 1)); |
427 | |
428 | BPolygon* bpoly = poly.GetBPolygon(); |
429 | |
430 | SetHighColor(150, 0, 0, 255); |
431 | StrokePolygon(bpoly, false); |
432 | FillPolygon(bpoly); |
433 | |
434 | delete bpoly; |
435 | } |
436 | } |
437 | |
438 | |
439 | void |
440 | BrushView::MessageReceived(BMessage* message) |
441 | { |
442 | // switch (message->what) { |
443 | // case HS_BRUSH_DRAGGED: { |
444 | // int32 size; |
445 | // brush_info* info; |
446 | // message->FindData("brush data",B_ANY_TYPE,(const void**)&info,&size); |
447 | // if (size == sizeof(brush_info)) { |
448 | // fBrush->ModifyBrush(*info); |
449 | // fBrush->PreviewBrush(fBrushPreview); |
450 | // Invalidate(); |
451 | // fBrush->CreateDiffBrushes(); |
452 | // if (Window() && Parent()) |
453 | // Window()->PostMessage(kBrushAltered, Parent()); |
454 | // } |
455 | // break; |
456 | // |
457 | // default: { |
458 | BView::MessageReceived(message); |
459 | // } break; |
460 | // } |
461 | } |
462 | |
463 | |
464 | void |
465 | BrushView::MouseDown(BPoint point) |
466 | { |
467 | BPoint c; |
468 | c.x = Bounds().Width() / 2.0; |
469 | c.y = Bounds().Height() / 2.0; |
470 | brush_info info = fBrush->GetInfo(); |
471 | uint32 buttons; |
472 | |
473 | GetMouse(&point,&buttons); |
474 | float angle = info.angle; |
Value stored to 'angle' during its initialization is never read | |
475 | float prev_angle; |
476 | if (point.x == c.x) |
477 | angle = 0; |
478 | else if (point.y == c.y) |
479 | angle = 90; |
480 | else { |
481 | angle = atan2(point.x-c.x,c.y-point.y) * 180 / M_PI3.14159265358979323846; |
482 | } |
483 | prev_angle = angle; |
484 | |
485 | if (true /*buttons == B_PRIMARY_MOUSE_BUTTON*/) { |
486 | while (buttons) { |
487 | if (angle != prev_angle) { |
488 | fBrush->ModifyBrush(info); |
489 | fBrush->PreviewBrush(fBrushPreview); |
490 | Window()->Lock(); |
491 | Draw(Bounds()); |
492 | Window()->Unlock(); |
493 | prev_angle = angle; |
494 | } |
495 | Window()->Lock(); |
496 | GetMouse(&point,&buttons); |
497 | Window()->Unlock(); |
498 | if (point.x == c.x) |
499 | angle = 0; |
500 | else if (point.y == c.y) |
501 | angle = 90; |
502 | else { |
503 | angle = atan2(point.x-c.x,c.y-point.y)*180/M_PI3.14159265358979323846; |
504 | } |
505 | if (angle > 90) |
506 | angle = -(90. - ((int32)angle % 90)); |
507 | if (angle < -90) |
508 | angle = 90. - ((int32)-angle % 90); |
509 | |
510 | if (modifiers() & B_LEFT_SHIFT_KEY) { |
511 | if (angle < 22 && angle > -22) |
512 | angle = 0; |
513 | else if (angle > 22 && angle < 75) |
514 | angle = 45; |
515 | else if (angle < -22 && angle > -75) |
516 | angle = -45; |
517 | else if (angle > 75) |
518 | angle = 90; |
519 | else if (angle < -75) |
520 | angle = -90; |
521 | } |
522 | |
523 | info.angle = angle; |
524 | snooze(20000); |
525 | } |
526 | |
527 | fBrush->CreateDiffBrushes(); |
528 | Window()->PostMessage(kBrushAltered, Parent()); |
529 | } /* else { |
530 | info = fBrush->GetInfo(); |
531 | BMessage* message = new BMessage(HS_BRUSH_DRAGGED); |
532 | message->AddData("brush data",B_ANY_TYPE,&info,sizeof(brush_info)); |
533 | DragMessage(message,BRect(0,0,fBrushPreview_WIDTH-1,fBrushPreview_HEIGHT-1)); |
534 | delete message; |
535 | } */ |
536 | } |
537 | |
538 | |
539 | void |
540 | BrushView::MouseMoved(BPoint where, uint32 transit, const BMessage* message) |
541 | { |
542 | if (Window() && Window()->Lock()) { |
543 | switch (transit) { |
544 | default: break; |
545 | case B_ENTERED_VIEW: { |
546 | fDrawControls = true; |
547 | Draw(Bounds()); |
548 | } break; |
549 | |
550 | case B_EXITED_VIEW: { |
551 | fDrawControls = false; |
552 | Draw(Bounds()); |
553 | } break; |
554 | } |
555 | |
556 | Window()->Unlock(); |
557 | } |
558 | } |
559 | |
560 | |
561 | void |
562 | BrushView::BrushModified() |
563 | { |
564 | fBrush->PreviewBrush(fBrushPreview); |
565 | Draw(Bounds()); |
566 | } |