1// ObjectView.cpp
2
3#include <stdio.h>
4
5#include <Application.h>
6#include <Bitmap.h>
7#include <Catalog.h>
8#include <Cursor.h>
9#include <Message.h>
10#include <MessageQueue.h>
11#include <Region.h>
12#include <Shape.h>
13#include <String.h>
14#include <Window.h>
15
16#include "ObjectView.h"
17#include "States.h"
18
19#undef B_TRANSLATION_CONTEXT
20#define B_TRANSLATION_CONTEXT "Playground"
21
22
23const unsigned char kMoveCursor[] = { 16, 1, 8, 8,
24	0x01, 0x80, 0x02, 0x40, 0x04, 0x20, 0x08, 0x10,
25	0x1e, 0x78, 0x2a, 0x54, 0x4e, 0x72, 0x80, 0x01,
26	0x80, 0x01, 0x4e, 0x72, 0x2a, 0x54, 0x1e, 0x78,
27	0x08, 0x10, 0x04, 0x20, 0x02, 0x40, 0x01, 0x80,
28
29	0x01, 0x80, 0x03, 0xc0, 0x07, 0xe0, 0x0f, 0xf0,
30	0x1f, 0xf8, 0x3b, 0xdc, 0x7f, 0xfe, 0xff, 0xff,
31	0xff, 0xff, 0x7f, 0xfe, 0x3b, 0xdc, 0x1f, 0xf8,
32	0x0f, 0xf0, 0x07, 0xe0, 0x03, 0xc0, 0x01, 0x80 };
33
34const unsigned char kGrabCursor[] = { 16, 1, 8, 9,
35	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
36	0x0d, 0xb0, 0x12, 0x4c, 0x10, 0x0a, 0x08, 0x02,
37	0x18, 0x02, 0x20, 0x02, 0x20, 0x02, 0x20, 0x04,
38	0x10, 0x04, 0x08, 0x08, 0x04, 0x08, 0x04, 0x08,
39
40	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
41	0x0d, 0xb0, 0x1f, 0xfc, 0x1f, 0xfe, 0x0f, 0xfe,
42	0x1f, 0xfe, 0x3f, 0xfe, 0x3f, 0xfe, 0x3f, 0xfc,
43	0x1f, 0xfc, 0x0f, 0xf8, 0x07, 0xf8, 0x07, 0xf8 };
44
45
46// constructor
47ObjectView::ObjectView(BRect frame, const char* name,
48					 uint32 resizeFlags, uint32 flags)
49	: BView(frame, name, resizeFlags, flags),
50	  fState(NULL),
51	  fObjectType(OBJECT_LINE),
52	  fStateList(20),
53	  fColor((rgb_color){ 0, 80, 255, 100 }),
54	  fDrawingMode(B_OP_ALPHA),
55	  fFill(false),
56	  fPenSize(10.0),
57	  fScrolling(false),
58	  fInitiatingDrag(false),
59	  fLastMousePos(0.0, 0.0)
60{
61
62	SetLowColor(tint_color(ui_color(B_PANEL_BACKGROUND_COLOR), B_LIGHTEN_1_TINT));
63
64//	BFont font;
65//	GetFont(&font);
66//	font.SetFamilyAndStyle("Bitstream Vera Serif", "Roman");
67//	font.SetSize(20.0);
68////	font.SetRotation(6.0);
69//	SetFont(&font, B_FONT_FAMILY_AND_STYLE | B_FONT_ROTATION | B_FONT_SIZE);
70
71//	State* state = State::StateFor(OBJECT_ROUND_RECT, fColor, B_OP_COPY,
72//								   false, 50.0);
73//	state->MouseDown(BPoint(15, 15));
74//	state->MouseMoved(BPoint(255, 305));
75//	state->MouseUp();
76//
77//	AddObject(state);
78
79	SetBlendingMode(B_CONSTANT_ALPHA, B_ALPHA_OVERLAY);
80}
81
82// destructor
83ObjectView::~ObjectView()
84{
85}
86
87// AttachedToWindow
88void
89ObjectView::AttachedToWindow()
90{
91	SetViewColor(B_TRANSPARENT_COLOR);
92}
93
94// DetachedFromWindow
95void
96ObjectView::DetachedFromWindow()
97{
98}
99
100// Draw
101void
102ObjectView::Draw(BRect updateRect)
103{
104	FillRect(updateRect, B_SOLID_LOW);
105
106//	SetHighColor(0, 0, 0);
107//	for (float i = 10; i < 200; i += 4.25) {
108//		StrokeLine(BPoint(i, 10), BPoint(i, 200));
109//		StrokeLine(BPoint(10, i), BPoint(200, i));
110//	}
111//
112//	SetHighColor(0, 0, 50);
113//	for (float i = 10; i < 200; i += 8.25) {
114//		FillRect(BRect(i, 10 + 230, i + 2, 200 + 230));
115//		FillRect(BRect(10, i + 230, 200, i + 2 + 230));
116//	}
117//
118//	rgb_color noTint = ui_color(B_PANEL_BACKGROUND_COLOR);
119//	rgb_color shadow = tint_color(noTint, B_DARKEN_2_TINT);
120//	rgb_color light = tint_color(noTint, B_LIGHTEN_MAX_TINT);
121
122	BRect r(Bounds());
123
124/*	BeginLineArray(4);
125	AddLine(BPoint(r.left, r.top),
126			BPoint(r.right, r.top), shadow);
127	AddLine(BPoint(r.right, r.top + 1),
128			BPoint(r.right, r.bottom), light);
129	AddLine(BPoint(r.right - 1, r.bottom),
130			BPoint(r.left, r.bottom), light);
131	AddLine(BPoint(r.left, r.bottom - 1),
132			BPoint(r.left, r.top + 1), shadow);
133	EndLineArray();*/
134
135//Sync();
136//	SetHighColor(200, 200, 200, 255);
137////	BRect rect(0.0, 0.0, 10.0, 11.0);
138//	int32 counter = 0;
139//	BRegion region;
140////	while (rect.top < r.bottom) {
141////		while (rect.left < r.right) {
142////			region.Include(rect);
143////			rect.OffsetBy(rect.Width() + 2, 0.0);
144////
145////			counter++;
146////		}
147////		rect.OffsetTo(0.0, rect.top + rect.Height() + 2);
148////	}
149//	BRect rect(0.0, 0.0, 0.0, 10.0);
150//	for (int32 i = 0; i < 100; i++) {
151//		region.Include(rect);
152//		rect.OffsetBy(rect.Width() + 1, 1.0);
153//		counter++;
154//	}
155//bigtime_t now = system_time();
156//	FillRegion(&region);
157//Sync();
158//printf("rendering %ld small rects (region: %ld): %lld\n", counter,
159//region.CountRects(), system_time() - now);
160
161	SetDrawingMode(B_OP_OVER);
162	SetHighColor(255, 0, 0, 128);
163
164	const char* message = B_TRANSLATE("Click and drag to draw an object");
165	float width = StringWidth(message);
166
167	BPoint p((r.Width() - width) / 2.0, r.Height() / 2.0);
168
169//Sync();
170//snooze(1000);
171//
172//bigtime_t now = system_time();
173//
174//#ifdef __HAIKU__
175//	BFont font;
176//	GetFont(&font);
177//	font.SetFalseBoldWidth(1.0);
178//	SetFont(&font, B_FONT_FALSE_BOLD_WIDTH);
179//	SetHighColor(0, 0, 0);
180//	DrawString(message, p);
181//
182//	font.SetFalseBoldWidth(0.0);
183//	SetFont(&font, B_FONT_FALSE_BOLD_WIDTH);
184//	SetHighColor(255, 0, 0);
185//#endif // __HAIKU__
186
187	DrawString(message, p);
188
189//Sync();
190//printf("Drawing Text: %lld\n", system_time() - now);
191
192//	r.OffsetTo(B_ORIGIN);
193//
194//now = system_time();
195//	int32 rectCount = 20;
196//	BeginLineArray(4 * rectCount);
197//	for (int32 i = 0; i < rectCount; i++) {
198//		r.InsetBy(5, 5);
199//
200//		AddLine(BPoint(r.left, r.top),
201//				BPoint(r.right, r.top), shadow);
202//		AddLine(BPoint(r.right, r.top + 1),
203//				BPoint(r.right, r.bottom), light);
204//		AddLine(BPoint(r.right - 1, r.bottom),
205//				BPoint(r.left, r.bottom), light);
206//		AddLine(BPoint(r.left, r.bottom - 1),
207//				BPoint(r.left, r.top + 1), shadow);
208//	}
209//	EndLineArray();
210//Sync();
211//printf("Drawing Lines: %lld\n", system_time() - now);
212
213//Flush();
214//Sync();
215//bigtime_t start = system_time();
216//SetDrawingMode(B_OP_ALPHA);
217//SetBlendingMode(B_CONSTANT_ALPHA, B_ALPHA_OVERLAY);
218//SetHighColor(0, 0, 255, 128);
219//FillRect(BRect(0, 0, 250, 300));
220//Sync();
221//printf("Alpha Fill: %lld\n", system_time() - start);
222
223	for (int32 i = 0; State* state = (State*)fStateList.ItemAt(i); i++)
224		state->Draw(this);
225//Sync();
226//printf("State: %lld\n", system_time() - start);
227}
228
229// MouseDown
230void
231ObjectView::MouseDown(BPoint where)
232{
233	uint32 buttons;
234	int32 clicks;
235//
236//	snooze(1000000);
237//	BMessageQueue* queue = Window()->MessageQueue();
238//	BMessage* msg;
239//	int32 count = 0;
240//	for (int32 i = 0; (msg = queue->FindMessage(i)); i++) {
241//		if (msg->what == B_MOUSE_MOVED)
242//			count++;
243//	}
244//	printf("B_MOUSE_MOVED count before GetMouse(): %ld\n", count);
245//
246//	GetMouse(&where, &buttons);
247//
248//	count = 0;
249//	for (int32 i = 0; (msg = queue->FindMessage(i)); i++) {
250//		if (msg->what == B_MOUSE_MOVED)
251//			count++;
252//	}
253//	printf("B_MOUSE_MOVED count after 1st GetMouse(): %ld\n", count);
254//
255//	GetMouse(&where, &buttons);
256//
257//	count = 0;
258//	for (int32 i = 0; (msg = queue->FindMessage(i)); i++) {
259//		if (msg->what == B_MOUSE_MOVED)
260//			count++;
261//	}
262//	printf("B_MOUSE_MOVED count after 2nd GetMouse(): %ld\n", count);
263//	return;
264
265//be_app->HideCursor();
266
267	Window()->CurrentMessage()->FindInt32("buttons", (int32*)&buttons);
268	Window()->CurrentMessage()->FindInt32("clicks", &clicks);
269//printf("ObjectView::MouseDown() - clicks: %ld\n", clicks);
270	fInitiatingDrag = buttons & B_SECONDARY_MOUSE_BUTTON;
271	fScrolling = !fInitiatingDrag && (buttons & B_TERTIARY_MOUSE_BUTTON);
272
273	SetMouseEventMask(B_POINTER_EVENTS, B_LOCK_WINDOW_FOCUS);
274
275	if (fScrolling  || fInitiatingDrag) {
276		fLastMousePos = where;
277	} else {
278		if (!fState)
279			AddObject(State::StateFor(fObjectType, fColor, fDrawingMode,
280									  fFill, fPenSize));
281
282		if (fState) {
283			fState->MouseDown(where);
284		}
285	}
286}
287
288// MouseUp
289void
290ObjectView::MouseUp(BPoint where)
291{
292//be_app->ShowCursor();
293
294	if (fScrolling) {
295		fScrolling = false;
296	} else {
297		if (fState) {
298			fState->MouseUp();
299		}
300	}
301}
302
303// MouseMoved
304void
305ObjectView::MouseMoved(BPoint where, uint32 transit,
306					   const BMessage* dragMessage)
307{
308//	BRect dirty(where, where);
309//	dirty.InsetBy(-10, -10);
310//	Invalidate(dirty);
311
312if (dragMessage) {
313//printf("ObjectView::MouseMoved(BPoint(%.1f, %.1f)) - DRAG MESSAGE\n", where.x, where.y);
314//Window()->CurrentMessage()->PrintToStream();
315} else {
316//printf("ObjectView::MouseMoved(BPoint(%.1f, %.1f))\n", where.x, where.y);
317}
318
319	if (fScrolling) {
320		BCursor cursor(kGrabCursor);
321		SetViewCursor(&cursor);
322
323		BPoint offset = fLastMousePos - where;
324		ScrollBy(offset.x, offset.y);
325		fLastMousePos = where + offset;
326	} else if (fInitiatingDrag) {
327		BPoint offset = fLastMousePos - where;
328		if (sqrtf(offset.x * offset.x + offset.y * offset.y) > 5.0) {
329			BMessage newDragMessage('drag');
330			BBitmap* dragBitmap = new BBitmap(BRect(0, 0, 40, 40), B_RGBA32,
331				true);
332			if (dragBitmap->Lock()) {
333				BView* helper = new BView(dragBitmap->Bounds(),
334					"offscreen view", B_FOLLOW_ALL, B_WILL_DRAW);
335				dragBitmap->AddChild(helper);
336				helper->SetDrawingMode(B_OP_ALPHA);
337				helper->SetBlendingMode(B_CONSTANT_ALPHA, B_ALPHA_COMPOSITE);
338
339				BRect r(helper->Bounds());
340				helper->SetHighColor(0, 0, 0, 128);
341				helper->StrokeRect(r);
342
343				helper->SetHighColor(200, 200, 200, 100);
344				r.InsetBy(1, 1);
345				helper->FillRect(r);
346
347				helper->SetHighColor(0, 0, 0, 255);
348				const char* text = B_TRANSLATE("Test");
349				float pos = (r.Width() - helper->StringWidth(text)) / 2;
350				helper->DrawString(text, BPoint(pos, 25));
351				helper->Sync();
352			}
353
354			DragMessage(&newDragMessage, dragBitmap, B_OP_ALPHA, B_ORIGIN,
355				this);
356			fInitiatingDrag = false;
357		}
358	} else {
359		BCursor cursor(kMoveCursor);
360		SetViewCursor(&cursor);
361
362		if (fState && fState->IsTracking()) {
363			BRect before = fState->Bounds();
364
365			fState->MouseMoved(where);
366
367			BRect after = fState->Bounds();
368			BRect invalid(before | after);
369			Invalidate(invalid);
370		}
371	}
372//	SetViewCursor();
373}
374
375// MessageReceived
376void
377ObjectView::MessageReceived(BMessage* message)
378{
379	switch (message->what) {
380		case 'drag':
381			printf("ObjectView::MessageReceived() - received drag message\n");
382			break;
383		default:
384			BView::MessageReceived(message);
385			break;
386	}
387}
388
389// SetState
390void
391ObjectView::SetState(State* state)
392{
393	if (fState != state) {
394		if (fState) {
395			fState->SetEditing(false);
396			Invalidate(fState->Bounds());
397		}
398
399		fState = state;
400
401		if (fState) {
402			fState->SetEditing(true);
403			Invalidate(fState->Bounds());
404		}
405	}
406}
407
408// SetObjectType
409void
410ObjectView::SetObjectType(int32 type)
411{
412	if (type != fObjectType) {
413		fObjectType = type;
414		SetState(NULL);
415	}
416}
417
418// AddObject
419void
420ObjectView::AddObject(State* state)
421{
422	if (state) {
423		fStateList.AddItem((void*)state);
424
425		BMessage message(MSG_OBJECT_ADDED);
426		message.AddPointer("object", state);
427		Window()->PostMessage(&message);
428
429		SetState(state);
430	}
431}
432
433// RemoveObject
434void
435ObjectView::RemoveObject(State* state)
436{
437	if (state && fStateList.RemoveItem((void*)state)) {
438		if (fState == state)
439			SetState(NULL);
440		else
441			Invalidate(state->Bounds());
442
443		Window()->PostMessage(MSG_OBJECT_COUNT_CHANGED);
444
445		delete state;
446	}
447}
448
449// CountObjects
450int32
451ObjectView::CountObjects() const
452{
453	return fStateList.CountItems();
454}
455
456// MakeEmpty
457void
458ObjectView::MakeEmpty()
459{
460	for (int32 i = 0; State* state = (State*)fStateList.ItemAt(i); i++)
461		delete state;
462	fStateList.MakeEmpty();
463
464	Window()->PostMessage(MSG_OBJECT_COUNT_CHANGED);
465
466	fState = NULL;
467
468	Invalidate();
469}
470
471// SetStateColor
472void
473ObjectView::SetStateColor(rgb_color color)
474{
475	if (color.red != fColor.red ||
476		color.green != fColor.green ||
477		color.blue != fColor.blue ||
478		color.alpha != fColor.alpha) {
479
480		fColor = color;
481
482		if (fState) {
483			fState->SetColor(fColor);
484			Invalidate(fState->Bounds());
485		}
486	}
487}
488
489// SetStateDrawingMode
490void
491ObjectView::SetStateDrawingMode(drawing_mode mode)
492{
493	if (fDrawingMode != mode) {
494		fDrawingMode = mode;
495
496		if (fState) {
497			fState->SetDrawingMode(fDrawingMode);
498			Invalidate(fState->Bounds());
499		}
500	}
501}
502
503// SetStateFill
504void
505ObjectView::SetStateFill(bool fill)
506{
507	if (fFill != fill) {
508		fFill = fill;
509
510		if (fState) {
511			BRect before = fState->Bounds();
512
513			fState->SetFill(fFill);
514
515			BRect after = fState->Bounds();
516			BRect invalid(before | after);
517			Invalidate(invalid);
518		}
519	}
520}
521
522// SetStatePenSize
523void
524ObjectView::SetStatePenSize(float penSize)
525{
526	if (fPenSize != penSize) {
527		fPenSize = penSize;
528
529		if (fState) {
530			BRect before = fState->Bounds();
531
532			fState->SetPenSize(fPenSize);
533
534			BRect after = fState->Bounds();
535			BRect invalid(before | after);
536			Invalidate(invalid);
537		}
538	}
539}
540