1 // main.cpp
2
3 #include <stdio.h>
4 #include <stdlib.h>
5
6 #include <Application.h>
7 #include <Alert.h>
8 #include <Bitmap.h>
9 #include <Box.h>
10 #include <Button.h>
11 #include <Catalog.h>
12 #include <CheckBox.h>
13 #include <ColorControl.h>
14 #include <ListItem.h>
15 #include <ListView.h>
16 #include <Menu.h>
17 #include <MenuBar.h>
18 #include <MenuField.h>
19 #include <MenuItem.h>
20 #include <PopUpMenu.h>
21 #include <ScrollBar.h>
22 #include <ScrollView.h>
23 #include <Slider.h>
24 #include <String.h>
25 #include <RadioButton.h>
26 #include <Region.h>
27 #include <TabView.h>
28 #include <TextControl.h>
29 #include <TextView.h>
30
31 #include "ObjectView.h"
32 #include "ObjectWindow.h"
33 #include "States.h"
34 //#include "StatusView.h"
35
36
37 #undef B_TRANSLATION_CONTEXT
38 #define B_TRANSLATION_CONTEXT "Playground"
39
40 enum {
41 MSG_SET_OBJECT_TYPE = 'stot',
42 MSG_SET_FILL_OR_STROKE = 'stfs',
43 MSG_SET_COLOR = 'stcl',
44 MSG_SET_PEN_SIZE = 'stps',
45 MSG_SET_DRAWING_MODE = 'stdm',
46
47 MSG_NEW_OBJECT = 'nobj',
48
49 MSG_UNDO = 'undo',
50 MSG_REDO = 'redo',
51
52 MSG_CLEAR = 'clir',
53
54 MSG_OBJECT_SELECTED = 'obsl',
55 MSG_REMOVE_OBJECT = 'rmob',
56 };
57
58 // ObjectItem
59 class ObjectItem : public BStringItem {
60 public:
ObjectItem(const char * name,State * object)61 ObjectItem(const char* name, State* object)
62 : BStringItem(name),
63 fObject(object)
64 {
65 }
66
Object() const67 State* Object() const
68 { return fObject; }
69
70 private:
71 State* fObject;
72 };
73
74 // ObjectListView
75 class ObjectListView : public BListView {
76 public:
ObjectListView(BRect frame,const char * name,list_view_type listType)77 ObjectListView(BRect frame, const char* name, list_view_type listType)
78 : BListView(frame, name, listType)
79 {
80 }
81
KeyDown(const char * bytes,int32 numBytes)82 virtual void KeyDown(const char* bytes, int32 numBytes)
83 {
84 switch (*bytes) {
85 case B_DELETE:
86 Window()->PostMessage(MSG_REMOVE_OBJECT);
87 break;
88 default:
89 BListView::KeyDown(bytes, numBytes);
90 }
91 }
92
InitiateDrag(BPoint point,int32 itemIndex,bool wasSelected)93 virtual bool InitiateDrag(BPoint point, int32 itemIndex, bool wasSelected)
94 {
95 printf("InitiateDrag(BPoint(%.1f, %.1f), itemIndex: %" B_PRId32
96 ", wasSelected: %d)\n", point.x, point.y, itemIndex,
97 wasSelected);
98 SwapItems(itemIndex, itemIndex + 1);
99 return true;
100 }
101
SelectionChanged()102 virtual void SelectionChanged()
103 {
104 // printf("SelectionChanged() - first selected: %ld\n", CurrentSelection(0));
105 }
106 };
107
108 // #pragma mark -
109
110 class TestView : public BView {
111 public:
TestView(BRect frame,const char * name,uint32 resizeMode,uint32 flags)112 TestView(BRect frame, const char* name, uint32 resizeMode, uint32 flags)
113 : BView(frame, name, resizeMode, flags)
114 {
115 }
116
AttachedToWindow()117 void AttachedToWindow()
118 {
119 SetViewColor(255, 0, 0);
120 }
121 };
122
123 // constructor
ObjectWindow(BRect frame,const char * name)124 ObjectWindow::ObjectWindow(BRect frame, const char* name)
125 : BWindow(frame, name, B_DOCUMENT_WINDOW_LOOK, B_NORMAL_WINDOW_FEEL,
126 B_ASYNCHRONOUS_CONTROLS | B_NOT_ZOOMABLE)
127 {
128 BRect b(Bounds());
129
130 b.bottom = b.top + 8;
131 BMenuBar* menuBar = new BMenuBar(b, "menu bar");
132 AddChild(menuBar);
133
134 BMenu* menu = new BMenu(B_TRANSLATE("File"));
135 menuBar->AddItem(menu);
136
137 menu->AddItem(new BMenu(B_TRANSLATE("Submenu")));
138
139 BMenuItem* menuItem = new BMenuItem(B_TRANSLATE("Quit"), new BMessage(B_QUIT_REQUESTED),
140 'Q');
141 menu->AddItem(menuItem);
142
143 b = Bounds();
144 b.top = menuBar->Bounds().bottom + 1;
145 b.right = ceilf((b.left + b.right) / 2.0);
146 BBox* bg = new BBox(b, "bg box", B_FOLLOW_TOP_BOTTOM, B_WILL_DRAW,
147 B_PLAIN_BORDER);
148
149 AddChild(bg);
150 bg->SetViewUIColor(B_PANEL_BACKGROUND_COLOR);
151
152 // object view occupies the right side of the window
153 b.left = b.right + 1.0;
154 b.right = Bounds().right - B_V_SCROLL_BAR_WIDTH;
155 b.bottom -= B_H_SCROLL_BAR_HEIGHT;
156 fObjectView = new ObjectView(b, "object view", B_FOLLOW_ALL,
157 B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE);
158 // wrap a scroll view around the object view
159 BScrollView* scrollView = new BScrollView("object scroller", fObjectView,
160 B_FOLLOW_ALL, 0, true, true, B_NO_BORDER);
161
162 if (BScrollBar* scrollBar = fObjectView->ScrollBar(B_VERTICAL)) {
163 scrollBar->SetRange(0.0, fObjectView->Bounds().Height());
164 scrollBar->SetProportion(0.5);
165 }
166 if (BScrollBar* scrollBar = fObjectView->ScrollBar(B_HORIZONTAL)) {
167 scrollBar->SetRange(0.0, fObjectView->Bounds().Width());
168 scrollBar->SetProportion(0.5);
169 }
170 AddChild(scrollView);
171
172 b = bg->Bounds();
173 // controls occupy the left side of the window
174 b.InsetBy(5.0, 5.0);
175 BBox* controlGroup = new BBox(b, "controls box",
176 B_FOLLOW_LEFT | B_FOLLOW_TOP_BOTTOM, B_WILL_DRAW, B_FANCY_BORDER);
177
178 controlGroup->SetLabel(B_TRANSLATE("Controls"));
179 bg->AddChild(controlGroup);
180
181 b = controlGroup->Bounds();
182 b.top += controlGroup->InnerFrame().top;
183 b.bottom = b.top + 25.0;
184 b.InsetBy(10.0, 10.0);
185 b.right = b.left + b.Width() / 2.0 - 5.0;
186
187 // new button
188 fNewB = new BButton(b, "new button", B_TRANSLATE("New object"),
189 new BMessage(MSG_NEW_OBJECT));
190 controlGroup->AddChild(fNewB);
191 SetDefaultButton(fNewB);
192
193 // clear button
194 b.OffsetBy(0, fNewB->Bounds().Height() + 5.0);
195 fClearB = new BButton(b, "clear button", B_TRANSLATE("Clear"), new BMessage(MSG_CLEAR));
196 controlGroup->AddChild(fClearB);
197
198 // object type radio buttons
199 BMessage* message;
200 BRadioButton* radioButton;
201
202 b.OffsetBy(0, fClearB->Bounds().Height() + 5.0);
203 message = new BMessage(MSG_SET_OBJECT_TYPE);
204 message->AddInt32("type", OBJECT_LINE);
205 radioButton = new BRadioButton(b, "radio 1", B_TRANSLATE("Line"), message);
206 controlGroup->AddChild(radioButton);
207
208 radioButton->SetValue(B_CONTROL_ON);
209
210 b.OffsetBy(0, radioButton->Bounds().Height() + 5.0);
211 message = new BMessage(MSG_SET_OBJECT_TYPE);
212 message->AddInt32("type", OBJECT_RECT);
213 radioButton = new BRadioButton(b, "radio 2", B_TRANSLATE("Rect"), message);
214 controlGroup->AddChild(radioButton);
215
216 b.OffsetBy(0, radioButton->Bounds().Height() + 5.0);
217 message = new BMessage(MSG_SET_OBJECT_TYPE);
218 message->AddInt32("type", OBJECT_ROUND_RECT);
219 radioButton = new BRadioButton(b, "radio 3", B_TRANSLATE("Round rect"), message);
220 controlGroup->AddChild(radioButton);
221
222 b.OffsetBy(0, radioButton->Bounds().Height() + 5.0);
223 message = new BMessage(MSG_SET_OBJECT_TYPE);
224 message->AddInt32("type", OBJECT_ELLIPSE);
225 radioButton = new BRadioButton(b, "radio 4", B_TRANSLATE("Ellipse"), message);
226 controlGroup->AddChild(radioButton);
227
228 // drawing mode
229 BPopUpMenu* popupMenu = new BPopUpMenu(B_TRANSLATE("<pick>"));
230
231 message = new BMessage(MSG_SET_DRAWING_MODE);
232 message->AddInt32("mode", B_OP_COPY);
233 popupMenu->AddItem(new BMenuItem(B_TRANSLATE("Copy"), message));
234
235 message = new BMessage(MSG_SET_DRAWING_MODE);
236 message->AddInt32("mode", B_OP_OVER);
237 popupMenu->AddItem(new BMenuItem(B_TRANSLATE("Over"), message));
238
239 message = new BMessage(MSG_SET_DRAWING_MODE);
240 message->AddInt32("mode", B_OP_INVERT);
241 popupMenu->AddItem(new BMenuItem(B_TRANSLATE("Invert"), message));
242
243 message = new BMessage(MSG_SET_DRAWING_MODE);
244 message->AddInt32("mode", B_OP_BLEND);
245 popupMenu->AddItem(new BMenuItem(B_TRANSLATE("Blend"), message));
246
247 message = new BMessage(MSG_SET_DRAWING_MODE);
248 message->AddInt32("mode", B_OP_SELECT);
249 popupMenu->AddItem(new BMenuItem(B_TRANSLATE("Select"), message));
250
251 message = new BMessage(MSG_SET_DRAWING_MODE);
252 message->AddInt32("mode", B_OP_ERASE);
253 popupMenu->AddItem(new BMenuItem(B_TRANSLATE("Erase"), message));
254
255 message = new BMessage(MSG_SET_DRAWING_MODE);
256 message->AddInt32("mode", B_OP_ADD);
257 popupMenu->AddItem(new BMenuItem(B_TRANSLATE("Add"), message));
258
259 message = new BMessage(MSG_SET_DRAWING_MODE);
260 message->AddInt32("mode", B_OP_SUBTRACT);
261 popupMenu->AddItem(new BMenuItem(B_TRANSLATE("Subtract"), message));
262
263 message = new BMessage(MSG_SET_DRAWING_MODE);
264 message->AddInt32("mode", B_OP_MIN);
265 popupMenu->AddItem(new BMenuItem(B_TRANSLATE("Min"), message));
266
267 message = new BMessage(MSG_SET_DRAWING_MODE);
268 message->AddInt32("mode", B_OP_MAX);
269 popupMenu->AddItem(new BMenuItem(B_TRANSLATE("Max"), message));
270
271 message = new BMessage(MSG_SET_DRAWING_MODE);
272 message->AddInt32("mode", B_OP_ALPHA);
273 BMenuItem* item = new BMenuItem(B_TRANSLATE("Alpha"), message);
274 item->SetMarked(true);
275 popupMenu->AddItem(item);
276
277 b.OffsetBy(0, radioButton->Bounds().Height() + 10.0);
278 fDrawingModeMF = new BMenuField(b, "drawing mode field", B_TRANSLATE("Mode:"),
279 popupMenu);
280
281 controlGroup->AddChild(fDrawingModeMF);
282
283 fDrawingModeMF->SetDivider(fDrawingModeMF->StringWidth(
284 fDrawingModeMF->Label()) + 10.0);
285
286 // color control
287 b.OffsetBy(0, fDrawingModeMF->Bounds().Height() + 10.0);
288 fColorControl = new BColorControl(b.LeftTop(), B_CELLS_16x16, 8,
289 "color control", new BMessage(MSG_SET_COLOR));
290 controlGroup->AddChild(fColorControl);
291
292 // alpha text control
293 b.OffsetBy(0, fColorControl-> Bounds().Height() + 5.0);
294 fAlphaTC = new BTextControl(b, "alpha text control", B_TRANSLATE("Alpha:"), "",
295 new BMessage(MSG_SET_COLOR));
296 controlGroup->AddChild(fAlphaTC);
297
298 // divide text controls the same
299 float mWidth = fDrawingModeMF->StringWidth(fDrawingModeMF->Label());
300 float aWidth = fAlphaTC->StringWidth(fAlphaTC->Label());
301
302 float width = max_c(mWidth, aWidth) + 20.0;
303 fDrawingModeMF->SetDivider(width);
304 fAlphaTC->SetDivider(width);
305
306 // fill check box
307 b.OffsetBy(0, fAlphaTC->Bounds().Height() + 5.0);
308 fFillCB = new BCheckBox(b, "fill check box", B_TRANSLATE("Fill"),
309 new BMessage(MSG_SET_FILL_OR_STROKE));
310 controlGroup->AddChild(fFillCB);
311
312 // pen size text control
313 b.OffsetBy(0, radioButton->Bounds().Height() + 5.0);
314 b.bottom = b.top + 10.0;//35;
315 fPenSizeS = new BSlider(b, "width slider", B_TRANSLATE("Width:"), NULL, 1, 100,
316 B_TRIANGLE_THUMB);
317 fPenSizeS->SetLimitLabels("1", "100");
318 fPenSizeS->SetModificationMessage(new BMessage(MSG_SET_PEN_SIZE));
319 fPenSizeS->SetHashMarks(B_HASH_MARKS_BOTTOM);
320 fPenSizeS->SetHashMarkCount(10);
321
322 controlGroup->AddChild(fPenSizeS);
323
324 // list view with objects
325 b = controlGroup->Bounds();
326 b.top += controlGroup->InnerFrame().top;
327 b.InsetBy(10.0, 10.0);
328 b.left = b.left + b.Width() / 2.0 + 6.0;
329 b.right -= B_V_SCROLL_BAR_WIDTH;
330 b.bottom = fDrawingModeMF->Frame().top - 10.0;
331
332 fObjectLV = new ObjectListView(b, "object list", B_SINGLE_SELECTION_LIST);
333 fObjectLV->SetSelectionMessage(new BMessage(MSG_OBJECT_SELECTED));
334
335 // wrap a scroll view around the list view
336 scrollView = new BScrollView("list scroller", fObjectLV,
337 B_FOLLOW_NONE, 0, false, true, B_FANCY_BORDER);
338 controlGroup->AddChild(scrollView);
339
340 // enforce some size limits
341 float minWidth = controlGroup->Frame().Width() + 30.0;
342 float minHeight = fPenSizeS->Frame().bottom
343 + menuBar->Bounds().Height() + 15.0;
344 float maxWidth = minWidth * 4.0;
345 float maxHeight = minHeight + 100;
346 SetSizeLimits(minWidth, maxWidth, minHeight, maxHeight);
347
348 ResizeTo(max_c(frame.Width(), minWidth), max_c(frame.Height(), minHeight));
349
350 _UpdateControls();
351 }
352
353 // destructor
~ObjectWindow()354 ObjectWindow::~ObjectWindow()
355 {
356 }
357
358 // QuitRequested
359 bool
QuitRequested()360 ObjectWindow::QuitRequested()
361 {
362 be_app->PostMessage(B_QUIT_REQUESTED);
363 return true;
364 }
365
366 // MessageReceived
367 void
MessageReceived(BMessage * message)368 ObjectWindow::MessageReceived(BMessage* message)
369 {
370 switch (message->what) {
371 case MSG_SET_OBJECT_TYPE: {
372 int32 type;
373 if (message->FindInt32("type", &type) >= B_OK) {
374 fObjectView->SetObjectType(type);
375 fFillCB->SetEnabled(type != OBJECT_LINE);
376 if (!fFillCB->IsEnabled())
377 fPenSizeS->SetEnabled(true);
378 else
379 fPenSizeS->SetEnabled(fFillCB->Value() == B_CONTROL_OFF);
380 }
381 break;
382 }
383 case MSG_SET_FILL_OR_STROKE: {
384 int32 value;
385 if (message->FindInt32("be:value", &value) >= B_OK) {
386 fObjectView->SetStateFill(value);
387 fPenSizeS->SetEnabled(value == B_CONTROL_OFF);
388 }
389 break;
390 }
391 case MSG_SET_COLOR:
392 fObjectView->SetStateColor(_GetColor());
393 _UpdateColorControls();
394 break;
395 case MSG_OBJECT_ADDED: {
396 State* object;
397 if (message->FindPointer("object", (void**)&object) >= B_OK) {
398 fObjectLV->AddItem(new ObjectItem("Object", object));
399 }
400 // fall through
401 }
402 case MSG_OBJECT_COUNT_CHANGED:
403 fClearB->SetEnabled(fObjectView->CountObjects() > 0);
404 break;
405 case MSG_OBJECT_SELECTED:
406 if (ObjectItem* item = (ObjectItem*)fObjectLV->ItemAt(fObjectLV->CurrentSelection(0))) {
407 fObjectView->SetState(item->Object());
408 fObjectView->SetStateColor(item->Object()->Color());
409 _UpdateControls();
410 } else
411 fObjectView->SetState(NULL);
412 break;
413 case MSG_REMOVE_OBJECT:
414 while (ObjectItem* item = (ObjectItem*)fObjectLV->ItemAt(fObjectLV->CurrentSelection(0))) {
415 fObjectView->RemoveObject(item->Object());
416 fObjectLV->RemoveItem(item);
417 delete item;
418 }
419 break;
420 case MSG_NEW_OBJECT:
421 fObjectView->SetState(NULL);
422 break;
423 case MSG_CLEAR: {
424 BAlert *alert = new BAlert("Playground",
425 B_TRANSLATE("Clear all drawing objects?"),
426 B_TRANSLATE("Cancel"), B_TRANSLATE("Clear"));
427 alert->SetShortcut(0, B_ESCAPE);
428 if (alert->Go() == 1) {
429 fObjectView->MakeEmpty();
430 fObjectLV->MakeEmpty();
431 }
432 break;
433 }
434 case MSG_SET_PEN_SIZE:
435 fObjectView->SetStatePenSize((float)fPenSizeS->Value());
436 break;
437 case MSG_SET_DRAWING_MODE: {
438 drawing_mode mode;
439 if (message->FindInt32("mode", (int32*)&mode) >= B_OK) {
440 fObjectView->SetStateDrawingMode(mode);
441 }
442 break;
443 }
444 default:
445 BWindow::MessageReceived(message);
446 }
447 }
448
449 // _UpdateControls
450 void
_UpdateControls() const451 ObjectWindow::_UpdateControls() const
452 {
453 _UpdateColorControls();
454
455 // update buttons
456 fClearB->SetEnabled(fObjectView->CountObjects() > 0);
457
458 fFillCB->SetEnabled(fObjectView->ObjectType() != OBJECT_LINE);
459
460 // pen size
461 fPenSizeS->SetValue((int32)fObjectView->StatePenSize());
462
463 // disable penSize if fill is on
464 if (!fFillCB->IsEnabled())
465 fPenSizeS->SetEnabled(true);
466 else
467 fPenSizeS->SetEnabled(fFillCB->Value() == B_CONTROL_OFF);
468 }
469
470 // _UpdateColorControls
471 void
_UpdateColorControls() const472 ObjectWindow::_UpdateColorControls() const
473 {
474 // update color
475 rgb_color c = fObjectView->StateColor();
476 char string[32];
477
478 sprintf(string, "%d", c.alpha);
479 fAlphaTC->SetText(string);
480
481 fColorControl->SetValue(c);
482 }
483
484 // _GetColor
485 rgb_color
_GetColor() const486 ObjectWindow::_GetColor() const
487 {
488 rgb_color c;
489
490 c = fColorControl->ValueAsColor();
491 c.alpha = max_c(0, min_c(255, atoi(fAlphaTC->Text())));
492
493 return c;
494 }
495
496