xref: /haiku/src/tests/servers/app/playground/ObjectWindow.cpp (revision bab64f65bb775dc23060e276f1f1c4498ab7af6c)
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