⛏️ index : haiku.git

// ObjectView.cpp

#include <stdio.h>

#include <Application.h>
#include <Bitmap.h>
#include <Catalog.h>
#include <Cursor.h>
#include <Message.h>
#include <MessageQueue.h>
#include <Region.h>
#include <Shape.h>
#include <String.h>
#include <Window.h>

#include "ObjectView.h"
#include "States.h"

#undef B_TRANSLATION_CONTEXT
#define B_TRANSLATION_CONTEXT "Playground"


const unsigned char kMoveCursor[] = { 16, 1, 8, 8,
	0x01, 0x80, 0x02, 0x40, 0x04, 0x20, 0x08, 0x10,
	0x1e, 0x78, 0x2a, 0x54, 0x4e, 0x72, 0x80, 0x01,
	0x80, 0x01, 0x4e, 0x72, 0x2a, 0x54, 0x1e, 0x78,
	0x08, 0x10, 0x04, 0x20, 0x02, 0x40, 0x01, 0x80,

	0x01, 0x80, 0x03, 0xc0, 0x07, 0xe0, 0x0f, 0xf0,
	0x1f, 0xf8, 0x3b, 0xdc, 0x7f, 0xfe, 0xff, 0xff,
	0xff, 0xff, 0x7f, 0xfe, 0x3b, 0xdc, 0x1f, 0xf8,
	0x0f, 0xf0, 0x07, 0xe0, 0x03, 0xc0, 0x01, 0x80 };

const unsigned char kGrabCursor[] = { 16, 1, 8, 9,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x0d, 0xb0, 0x12, 0x4c, 0x10, 0x0a, 0x08, 0x02,
	0x18, 0x02, 0x20, 0x02, 0x20, 0x02, 0x20, 0x04,
	0x10, 0x04, 0x08, 0x08, 0x04, 0x08, 0x04, 0x08,

	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x0d, 0xb0, 0x1f, 0xfc, 0x1f, 0xfe, 0x0f, 0xfe,
	0x1f, 0xfe, 0x3f, 0xfe, 0x3f, 0xfe, 0x3f, 0xfc,
	0x1f, 0xfc, 0x0f, 0xf8, 0x07, 0xf8, 0x07, 0xf8 };


// constructor
ObjectView::ObjectView(BRect frame, const char* name,
					 uint32 resizeFlags, uint32 flags)
	: BView(frame, name, resizeFlags, flags),
	  fState(NULL),
	  fObjectType(OBJECT_LINE),
	  fStateList(20),
	  fColor((rgb_color){ 0, 80, 255, 100 }),
	  fDrawingMode(B_OP_ALPHA),
	  fFill(false),
	  fPenSize(10.0),
	  fScrolling(false),
	  fInitiatingDrag(false),
	  fLastMousePos(0.0, 0.0)
{

	SetLowColor(tint_color(ui_color(B_PANEL_BACKGROUND_COLOR), B_LIGHTEN_1_TINT));

//	BFont font;
//	GetFont(&font);
//	font.SetFamilyAndStyle("Bitstream Vera Serif", "Roman");
//	font.SetSize(20.0);
////	font.SetRotation(6.0);
//	SetFont(&font, B_FONT_FAMILY_AND_STYLE | B_FONT_ROTATION | B_FONT_SIZE);

//	State* state = State::StateFor(OBJECT_ROUND_RECT, fColor, B_OP_COPY,
//								   false, 50.0);
//	state->MouseDown(BPoint(15, 15));
//	state->MouseMoved(BPoint(255, 305));
//	state->MouseUp();
//
//	AddObject(state);

	SetBlendingMode(B_CONSTANT_ALPHA, B_ALPHA_OVERLAY);
}

// destructor
ObjectView::~ObjectView()
{
}

// AttachedToWindow
void
ObjectView::AttachedToWindow()
{
	SetViewColor(B_TRANSPARENT_COLOR);
}

// DetachedFromWindow
void
ObjectView::DetachedFromWindow()
{
}

// Draw
void
ObjectView::Draw(BRect updateRect)
{
	FillRect(updateRect, B_SOLID_LOW);

//	SetHighColor(0, 0, 0);
//	for (float i = 10; i < 200; i += 4.25) {
//		StrokeLine(BPoint(i, 10), BPoint(i, 200));
//		StrokeLine(BPoint(10, i), BPoint(200, i));
//	}
//
//	SetHighColor(0, 0, 50);
//	for (float i = 10; i < 200; i += 8.25) {
//		FillRect(BRect(i, 10 + 230, i + 2, 200 + 230));
//		FillRect(BRect(10, i + 230, 200, i + 2 + 230));
//	}
//
//	rgb_color noTint = ui_color(B_PANEL_BACKGROUND_COLOR);
//	rgb_color shadow = tint_color(noTint, B_DARKEN_2_TINT);
//	rgb_color light = tint_color(noTint, B_LIGHTEN_MAX_TINT);

	BRect r(Bounds());

/*	BeginLineArray(4);
	AddLine(BPoint(r.left, r.top),
			BPoint(r.right, r.top), shadow);
	AddLine(BPoint(r.right, r.top + 1),
			BPoint(r.right, r.bottom), light);
	AddLine(BPoint(r.right - 1, r.bottom),
			BPoint(r.left, r.bottom), light);
	AddLine(BPoint(r.left, r.bottom - 1),
			BPoint(r.left, r.top + 1), shadow);
	EndLineArray();*/

//Sync();
//	SetHighColor(200, 200, 200, 255);
////	BRect rect(0.0, 0.0, 10.0, 11.0);
//	int32 counter = 0;
//	BRegion region;
////	while (rect.top < r.bottom) {
////		while (rect.left < r.right) {
////			region.Include(rect);
////			rect.OffsetBy(rect.Width() + 2, 0.0);
////
////			counter++;
////		}
////		rect.OffsetTo(0.0, rect.top + rect.Height() + 2);
////	}
//	BRect rect(0.0, 0.0, 0.0, 10.0);
//	for (int32 i = 0; i < 100; i++) {
//		region.Include(rect);
//		rect.OffsetBy(rect.Width() + 1, 1.0);
//		counter++;
//	}
//bigtime_t now = system_time();
//	FillRegion(&region);
//Sync();
//printf("rendering %ld small rects (region: %ld): %lld\n", counter,
//region.CountRects(), system_time() - now);

	SetDrawingMode(B_OP_OVER);
	SetHighColor(255, 0, 0, 128);

	const char* message = B_TRANSLATE("Click and drag to draw an object");
	float width = StringWidth(message);

	BPoint p((r.Width() - width) / 2.0, r.Height() / 2.0);

//Sync();
//snooze(1000);
//
//bigtime_t now = system_time();
//
//#ifdef __HAIKU__
//	BFont font;
//	GetFont(&font);
//	font.SetFalseBoldWidth(1.0);
//	SetFont(&font, B_FONT_FALSE_BOLD_WIDTH);
//	SetHighColor(0, 0, 0);
//	DrawString(message, p);
//
//	font.SetFalseBoldWidth(0.0);
//	SetFont(&font, B_FONT_FALSE_BOLD_WIDTH);
//	SetHighColor(255, 0, 0);
//#endif // __HAIKU__

	DrawString(message, p);

//Sync();
//printf("Drawing Text: %lld\n", system_time() - now);

//	r.OffsetTo(B_ORIGIN);
//
//now = system_time();
//	int32 rectCount = 20;
//	BeginLineArray(4 * rectCount);
//	for (int32 i = 0; i < rectCount; i++) {
//		r.InsetBy(5, 5);
//	
//		AddLine(BPoint(r.left, r.top),
//				BPoint(r.right, r.top), shadow);
//		AddLine(BPoint(r.right, r.top + 1),
//				BPoint(r.right, r.bottom), light);
//		AddLine(BPoint(r.right - 1, r.bottom),
//				BPoint(r.left, r.bottom), light);
//		AddLine(BPoint(r.left, r.bottom - 1),
//				BPoint(r.left, r.top + 1), shadow);
//	}
//	EndLineArray();
//Sync();
//printf("Drawing Lines: %lld\n", system_time() - now);

//Flush();
//Sync();
//bigtime_t start = system_time();
//SetDrawingMode(B_OP_ALPHA);
//SetBlendingMode(B_CONSTANT_ALPHA, B_ALPHA_OVERLAY);
//SetHighColor(0, 0, 255, 128);
//FillRect(BRect(0, 0, 250, 300));
//Sync();
//printf("Alpha Fill: %lld\n", system_time() - start);

	for (int32 i = 0; State* state = (State*)fStateList.ItemAt(i); i++)
		state->Draw(this);
//Sync();
//printf("State: %lld\n", system_time() - start);
}

// MouseDown
void
ObjectView::MouseDown(BPoint where)
{
	uint32 buttons;
	int32 clicks;
//
//	snooze(1000000);
//	BMessageQueue* queue = Window()->MessageQueue();
//	BMessage* msg;
//	int32 count = 0;
//	for (int32 i = 0; (msg = queue->FindMessage(i)); i++) {
//		if (msg->what == B_MOUSE_MOVED)
//			count++;
//	}
//	printf("B_MOUSE_MOVED count before GetMouse(): %ld\n", count);
//
//	GetMouse(&where, &buttons);
//
//	count = 0;
//	for (int32 i = 0; (msg = queue->FindMessage(i)); i++) {
//		if (msg->what == B_MOUSE_MOVED)
//			count++;
//	}
//	printf("B_MOUSE_MOVED count after 1st GetMouse(): %ld\n", count);
//
//	GetMouse(&where, &buttons);
//
//	count = 0;
//	for (int32 i = 0; (msg = queue->FindMessage(i)); i++) {
//		if (msg->what == B_MOUSE_MOVED)
//			count++;
//	}
//	printf("B_MOUSE_MOVED count after 2nd GetMouse(): %ld\n", count);
//	return;

//be_app->HideCursor();

	Window()->CurrentMessage()->FindInt32("buttons", (int32*)&buttons);
	Window()->CurrentMessage()->FindInt32("clicks", &clicks);
//printf("ObjectView::MouseDown() - clicks: %ld\n", clicks);
	fInitiatingDrag = buttons & B_SECONDARY_MOUSE_BUTTON;
	fScrolling = !fInitiatingDrag && (buttons & B_TERTIARY_MOUSE_BUTTON);

	SetMouseEventMask(B_POINTER_EVENTS, B_LOCK_WINDOW_FOCUS);

	if (fScrolling  || fInitiatingDrag) {
		fLastMousePos = where;
	} else {
		if (!fState)
			AddObject(State::StateFor(fObjectType, fColor, fDrawingMode,
									  fFill, fPenSize));
	
		if (fState) {
			fState->MouseDown(where);
		}
	}
}

// MouseUp
void
ObjectView::MouseUp(BPoint where)
{
//be_app->ShowCursor();

	if (fScrolling) {
		fScrolling = false;
	} else {
		if (fState) {
			fState->MouseUp();
		}
	}
}

// MouseMoved
void
ObjectView::MouseMoved(BPoint where, uint32 transit,
					   const BMessage* dragMessage)
{
//	BRect dirty(where, where);
//	dirty.InsetBy(-10, -10);
//	Invalidate(dirty);
	
if (dragMessage) {
//printf("ObjectView::MouseMoved(BPoint(%.1f, %.1f)) - DRAG MESSAGE\n", where.x, where.y);
//Window()->CurrentMessage()->PrintToStream();
} else {
//printf("ObjectView::MouseMoved(BPoint(%.1f, %.1f))\n", where.x, where.y);
}

	if (fScrolling) {
		BCursor cursor(kGrabCursor);
		SetViewCursor(&cursor);
	
		BPoint offset = fLastMousePos - where;
		ScrollBy(offset.x, offset.y);
		fLastMousePos = where + offset;
	} else if (fInitiatingDrag) {
		BPoint offset = fLastMousePos - where;
		if (sqrtf(offset.x * offset.x + offset.y * offset.y) > 5.0) {
			BMessage newDragMessage('drag');
			BBitmap* dragBitmap = new BBitmap(BRect(0, 0, 40, 40), B_RGBA32,
				true);
			if (dragBitmap->Lock()) {
				BView* helper = new BView(dragBitmap->Bounds(),
					"offscreen view", B_FOLLOW_ALL, B_WILL_DRAW);
				dragBitmap->AddChild(helper);
				helper->SetDrawingMode(B_OP_ALPHA);
				helper->SetBlendingMode(B_CONSTANT_ALPHA, B_ALPHA_COMPOSITE);

				BRect r(helper->Bounds());
				helper->SetHighColor(0, 0, 0, 128);
				helper->StrokeRect(r);

				helper->SetHighColor(200, 200, 200, 100);
				r.InsetBy(1, 1);
				helper->FillRect(r);

				helper->SetHighColor(0, 0, 0, 255);
				const char* text = B_TRANSLATE("Test");
				float pos = (r.Width() - helper->StringWidth(text)) / 2;
				helper->DrawString(text, BPoint(pos, 25));
				helper->Sync();
			}
			
			DragMessage(&newDragMessage, dragBitmap, B_OP_ALPHA, B_ORIGIN,
				this);
			fInitiatingDrag = false;
		}
	} else {
		BCursor cursor(kMoveCursor);
		SetViewCursor(&cursor);
	
		if (fState && fState->IsTracking()) {
			BRect before = fState->Bounds();
	
			fState->MouseMoved(where);
	
			BRect after = fState->Bounds();
			BRect invalid(before | after);
			Invalidate(invalid);
		}
	}
//	SetViewCursor();
}

// MessageReceived
void
ObjectView::MessageReceived(BMessage* message)
{
	switch (message->what) {
		case 'drag':
			printf("ObjectView::MessageReceived() - received drag message\n");
			break;
		default:
			BView::MessageReceived(message);
			break;
	}
}

// SetState
void
ObjectView::SetState(State* state)
{
	if (fState != state) {
		if (fState) {
			fState->SetEditing(false);
			Invalidate(fState->Bounds());
		}
	
		fState = state;
	
		if (fState) {
			fState->SetEditing(true);
			Invalidate(fState->Bounds());
		}
	}
}

// SetObjectType
void
ObjectView::SetObjectType(int32 type)
{
	if (type != fObjectType) {
		fObjectType = type;
		SetState(NULL);
	}
}

// AddObject
void
ObjectView::AddObject(State* state)
{
	if (state) {
		fStateList.AddItem((void*)state);

		BMessage message(MSG_OBJECT_ADDED);
		message.AddPointer("object", state);
		Window()->PostMessage(&message);

		SetState(state);
	}
}

// RemoveObject
void
ObjectView::RemoveObject(State* state)
{
	if (state && fStateList.RemoveItem((void*)state)) {
		if (fState == state)
			SetState(NULL);
		else
			Invalidate(state->Bounds());

		Window()->PostMessage(MSG_OBJECT_COUNT_CHANGED);

		delete state;
	}
}

// CountObjects
int32
ObjectView::CountObjects() const
{
	return fStateList.CountItems();
}

// MakeEmpty
void
ObjectView::MakeEmpty()
{
	for (int32 i = 0; State* state = (State*)fStateList.ItemAt(i); i++)
		delete state;
	fStateList.MakeEmpty();

	Window()->PostMessage(MSG_OBJECT_COUNT_CHANGED);

	fState = NULL;

	Invalidate();
}

// SetStateColor
void
ObjectView::SetStateColor(rgb_color color)
{
	if (color.red != fColor.red ||
		color.green != fColor.green ||
		color.blue != fColor.blue ||
		color.alpha != fColor.alpha) {

		fColor = color;

		if (fState) {
			fState->SetColor(fColor);
			Invalidate(fState->Bounds());
		}
	}
}

// SetStateDrawingMode
void
ObjectView::SetStateDrawingMode(drawing_mode mode)
{
	if (fDrawingMode != mode) {
		fDrawingMode = mode;
	
		if (fState) {
			fState->SetDrawingMode(fDrawingMode);
			Invalidate(fState->Bounds());
		}
	}
}

// SetStateFill
void
ObjectView::SetStateFill(bool fill)
{
	if (fFill != fill) {
		fFill = fill;
	
		if (fState) {
			BRect before = fState->Bounds();
	
			fState->SetFill(fFill);
	
			BRect after = fState->Bounds();
			BRect invalid(before | after);
			Invalidate(invalid);
		}
	}
}

// SetStatePenSize
void
ObjectView::SetStatePenSize(float penSize)
{
	if (fPenSize != penSize) {
		fPenSize = penSize;
	
		if (fState) {
			BRect before = fState->Bounds();
	
			fState->SetPenSize(fPenSize);
	
			BRect after = fState->Bounds();
			BRect invalid(before | after);
			Invalidate(invalid);
		}
	}
}