headers/bsd: Add sys/queue.h.
[haiku.git] / src / tests / servers / app / playground / ObjectWindow.cpp
blobcd1bf5fd32b6510ab82befddf4f186130934f23d
1 // main.cpp
3 #include <stdio.h>
4 #include <stdlib.h>
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>
31 #include "ObjectView.h"
32 #include "ObjectWindow.h"
33 #include "States.h"
34 //#include "StatusView.h"
37 #undef B_TRANSLATION_CONTEXT
38 #define B_TRANSLATION_CONTEXT "Playground"
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',
47 MSG_NEW_OBJECT = 'nobj',
49 MSG_UNDO = 'undo',
50 MSG_REDO = 'redo',
52 MSG_CLEAR = 'clir',
54 MSG_OBJECT_SELECTED = 'obsl',
55 MSG_REMOVE_OBJECT = 'rmob',
58 // ObjectItem
59 class ObjectItem : public BStringItem {
60 public:
61 ObjectItem(const char* name, State* object)
62 : BStringItem(name),
63 fObject(object)
67 State* Object() const
68 { return fObject; }
70 private:
71 State* fObject;
74 // ObjectListView
75 class ObjectListView : public BListView {
76 public:
77 ObjectListView(BRect frame, const char* name, list_view_type listType)
78 : BListView(frame, name, listType)
82 virtual void KeyDown(const char* bytes, int32 numBytes)
84 switch (*bytes) {
85 case B_DELETE:
86 Window()->PostMessage(MSG_REMOVE_OBJECT);
87 break;
88 default:
89 BListView::KeyDown(bytes, numBytes);
93 virtual bool InitiateDrag(BPoint point, int32 itemIndex, bool wasSelected)
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;
102 virtual void SelectionChanged()
104 // printf("SelectionChanged() - first selected: %ld\n", CurrentSelection(0));
108 // #pragma mark -
110 class TestView : public BView {
111 public:
112 TestView(BRect frame, const char* name, uint32 resizeMode, uint32 flags)
113 : BView(frame, name, resizeMode, flags)
117 void AttachedToWindow()
119 SetViewColor(255, 0, 0);
123 // constructor
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)
128 BRect b(Bounds());
130 b.bottom = b.top + 8;
131 BMenuBar* menuBar = new BMenuBar(b, "menu bar");
132 AddChild(menuBar);
134 BMenu* menu = new BMenu(B_TRANSLATE("File"));
135 menuBar->AddItem(menu);
137 menu->AddItem(new BMenu(B_TRANSLATE("Submenu")));
139 BMenuItem* menuItem = new BMenuItem(B_TRANSLATE("Quit"), new BMessage(B_QUIT_REQUESTED),
140 'Q');
141 menu->AddItem(menuItem);
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);
149 AddChild(bg);
150 bg->SetViewUIColor(B_PANEL_BACKGROUND_COLOR);
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);
162 if (BScrollBar* scrollBar = fObjectView->ScrollBar(B_VERTICAL)) {
163 scrollBar->SetRange(0.0, fObjectView->Bounds().Height());
164 scrollBar->SetProportion(0.5);
166 if (BScrollBar* scrollBar = fObjectView->ScrollBar(B_HORIZONTAL)) {
167 scrollBar->SetRange(0.0, fObjectView->Bounds().Width());
168 scrollBar->SetProportion(0.5);
170 AddChild(scrollView);
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);
178 controlGroup->SetLabel(B_TRANSLATE("Controls"));
179 bg->AddChild(controlGroup);
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;
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);
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);
198 // object type radio buttons
199 BMessage* message;
200 BRadioButton* radioButton;
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);
208 radioButton->SetValue(B_CONTROL_ON);
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);
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);
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);
228 // drawing mode
229 BPopUpMenu* popupMenu = new BPopUpMenu(B_TRANSLATE("<pick>"));
231 message = new BMessage(MSG_SET_DRAWING_MODE);
232 message->AddInt32("mode", B_OP_COPY);
233 popupMenu->AddItem(new BMenuItem(B_TRANSLATE("Copy"), message));
235 message = new BMessage(MSG_SET_DRAWING_MODE);
236 message->AddInt32("mode", B_OP_OVER);
237 popupMenu->AddItem(new BMenuItem(B_TRANSLATE("Over"), message));
239 message = new BMessage(MSG_SET_DRAWING_MODE);
240 message->AddInt32("mode", B_OP_INVERT);
241 popupMenu->AddItem(new BMenuItem(B_TRANSLATE("Invert"), message));
243 message = new BMessage(MSG_SET_DRAWING_MODE);
244 message->AddInt32("mode", B_OP_BLEND);
245 popupMenu->AddItem(new BMenuItem(B_TRANSLATE("Blend"), message));
247 message = new BMessage(MSG_SET_DRAWING_MODE);
248 message->AddInt32("mode", B_OP_SELECT);
249 popupMenu->AddItem(new BMenuItem(B_TRANSLATE("Select"), message));
251 message = new BMessage(MSG_SET_DRAWING_MODE);
252 message->AddInt32("mode", B_OP_ERASE);
253 popupMenu->AddItem(new BMenuItem(B_TRANSLATE("Erase"), message));
255 message = new BMessage(MSG_SET_DRAWING_MODE);
256 message->AddInt32("mode", B_OP_ADD);
257 popupMenu->AddItem(new BMenuItem(B_TRANSLATE("Add"), message));
259 message = new BMessage(MSG_SET_DRAWING_MODE);
260 message->AddInt32("mode", B_OP_SUBTRACT);
261 popupMenu->AddItem(new BMenuItem(B_TRANSLATE("Subtract"), message));
263 message = new BMessage(MSG_SET_DRAWING_MODE);
264 message->AddInt32("mode", B_OP_MIN);
265 popupMenu->AddItem(new BMenuItem(B_TRANSLATE("Min"), message));
267 message = new BMessage(MSG_SET_DRAWING_MODE);
268 message->AddInt32("mode", B_OP_MAX);
269 popupMenu->AddItem(new BMenuItem(B_TRANSLATE("Max"), message));
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);
277 b.OffsetBy(0, radioButton->Bounds().Height() + 10.0);
278 fDrawingModeMF = new BMenuField(b, "drawing mode field", B_TRANSLATE("Mode:"),
279 popupMenu);
281 controlGroup->AddChild(fDrawingModeMF);
283 fDrawingModeMF->SetDivider(fDrawingModeMF->StringWidth(
284 fDrawingModeMF->Label()) + 10.0);
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);
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);
298 // divide text controls the same
299 float mWidth = fDrawingModeMF->StringWidth(fDrawingModeMF->Label());
300 float aWidth = fAlphaTC->StringWidth(fAlphaTC->Label());
302 float width = max_c(mWidth, aWidth) + 20.0;
303 fDrawingModeMF->SetDivider(width);
304 fAlphaTC->SetDivider(width);
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);
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);
322 controlGroup->AddChild(fPenSizeS);
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;
332 fObjectLV = new ObjectListView(b, "object list", B_SINGLE_SELECTION_LIST);
333 fObjectLV->SetSelectionMessage(new BMessage(MSG_OBJECT_SELECTED));
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);
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);
348 ResizeTo(max_c(frame.Width(), minWidth), max_c(frame.Height(), minHeight));
350 _UpdateControls();
353 // destructor
354 ObjectWindow::~ObjectWindow()
358 // QuitRequested
359 bool
360 ObjectWindow::QuitRequested()
362 be_app->PostMessage(B_QUIT_REQUESTED);
363 return true;
366 // MessageReceived
367 void
368 ObjectWindow::MessageReceived(BMessage* message)
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);
381 break;
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);
389 break;
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));
400 // fall through
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;
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();
432 break;
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);
442 break;
444 default:
445 BWindow::MessageReceived(message);
449 // _UpdateControls
450 void
451 ObjectWindow::_UpdateControls() const
453 _UpdateColorControls();
455 // update buttons
456 fClearB->SetEnabled(fObjectView->CountObjects() > 0);
458 fFillCB->SetEnabled(fObjectView->ObjectType() != OBJECT_LINE);
460 // pen size
461 fPenSizeS->SetValue((int32)fObjectView->StatePenSize());
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);
470 // _UpdateColorControls
471 void
472 ObjectWindow::_UpdateColorControls() const
474 // update color
475 rgb_color c = fObjectView->StateColor();
476 char string[32];
478 sprintf(string, "%d", c.alpha);
479 fAlphaTC->SetText(string);
481 fColorControl->SetValue(c);
484 // _GetColor
485 rgb_color
486 ObjectWindow::_GetColor() const
488 rgb_color c;
490 c = fColorControl->ValueAsColor();
491 c.alpha = max_c(0, min_c(255, atoi(fAlphaTC->Text())));
493 return c;