⛏️ index : haiku.git

/*
 * Copyright 2006-2009, Haiku, Inc. All Rights Reserved.
 * Distributed under the terms of the MIT License.
 *
 * Authors:
 *		Mikael Konradson, mikael.konradson@gmail.com
 */


#include "FontDemoView.h"

#include <math.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#include <Catalog.h>
#include <Bitmap.h>
#include <Font.h>
#include <Message.h>
#include <Shape.h>
#include <String.h>
#include <StackOrHeapArray.h>

#include "messages.h"

#undef B_TRANSLATION_CONTEXT
#define B_TRANSLATION_CONTEXT "FontDemoView"

FontDemoView::FontDemoView(BRect rect)
	: BView(rect, "FontDemoView", B_FOLLOW_ALL, B_WILL_DRAW | B_FRAME_EVENTS),
	fFontSize(50.0),
	fSpacing(0.0),
	fOutLineLevel(0),
	fDrawingMode(B_OP_COPY),
	fBoundingBoxes(false),
	fDrawShapes(false),
	fShapes(NULL)
{
	SetViewUIColor(B_DOCUMENT_BACKGROUND_COLOR);
	SetHighUIColor(B_DOCUMENT_TEXT_COLOR);

	BString setStr = B_TRANSLATE("Haiku, Inc.");
	SetString(setStr);
	SetFontSize(fFontSize);
	SetAntialiasing(true);
}


FontDemoView::~FontDemoView()
{
	free(fShapes);
}


void
FontDemoView::FrameResized(float width, float height)
{
	// TODO: We shouldnt invalidate the whole view when bounding boxes are
	// working as wanted
	Invalidate(/*fBoxRegion.Frame()*/);
	BView::FrameResized(width, height);
}


void
FontDemoView::Draw(BRect updateRect)
{
	SetDrawingMode(B_OP_COPY);

	BRect rect = Bounds();

	if (!fString)
		return;

	SetFont(&fFont, B_FONT_ALL);

	const size_t size = fString.CountChars();
	BStackOrHeapArray<BRect, 64> boundBoxes(size);

	if (OutLineLevel())
		fFont.GetGlyphShapes(fString, size, fShapes);
	else
		fFont.GetBoundingBoxesAsGlyphs(fString, size, B_SCREEN_METRIC, boundBoxes);

	float escapementArray[size];
	//struct escapement_delta escapeDeltas[size];
	struct edge_info edgeInfo[size];
/*
	for (size_t j = 0; j < size; j++) {
		escapeDeltas[j].nonspace = 0.0f;
		escapeDeltas[j].space = 0.0f;
	}
*/
	fFont.GetEdges(fString.String(), size, edgeInfo);
	fFont.GetEscapements(fString.String(), size, /*escapeDeltas,*/ escapementArray);

	font_height fh;
	fFont.GetHeight(&fh);

	float xCoordArray[size];
	float yCoordArray[size];

	float yCoord = (rect.Height() + fh.ascent - fh.descent) / 2;
	float xCoord = -rect.Width() / 2;
	const float xCenter = xCoord * -1;
	const float r = Rotation() * (M_PI / 180.0);
	const float cosinus = cos(r);
	const float sinus = -sin(r);

	// When the bounding boxes workes properly we will invalidate only the
	// region area instead of the whole view.

	fBoxRegion.MakeEmpty();

	for (size_t i = 0; i < size; i++) {
		xCoordArray[i] = 0.0f;
		yCoordArray[i] = 0.0f;

		yCoordArray[i] = sinus * (xCoord - xCoordArray[i]);
		xCoordArray[i] = cosinus * xCoord;

		xCoordArray[i] += xCenter;
		yCoordArray[i] += yCoord;

		boundBoxes[i].OffsetBy(xCoordArray[i], yCoordArray[i]);

		if (OutLineLevel()) {
			MovePenTo(xCoordArray[i], yCoordArray[i]);
			FillShape(fShapes[i]);
			SetPenSize(OutLineLevel());
			StrokeShape(fShapes[i]);
		} else {
			SetDrawingMode(fDrawingMode);
			int32 charLength;
			const char* charAt = fString.CharAt(i, &charLength);
			DrawString(charAt, charLength,
				BPoint(xCoordArray[i], yCoordArray[i]));
		}

		if (BoundingBoxes() && !OutLineLevel()) {
			if (i % 2)
				SetHighColor(0, 255, 0);
			else
				SetHighColor(255, 0, 0);
			SetDrawingMode(B_OP_COPY);
			StrokeRect(boundBoxes[i]);
		}

		// add the bounding to the region.
		fBoxRegion.Include(boundBoxes[i]);

		xCoord += (escapementArray[i] /*+ escapeDeltas[i].nonspace + escapeDeltas[i].space*/)
			* FontSize() + Spacing();
		//printf("xCoord %f\n", xCoord);
	}
}


void
FontDemoView::MessageReceived(BMessage* msg)
{
	switch (msg->what) {
		case TEXT_CHANGED_MSG:
		{
			BString text;
			if (msg->FindString("_text", &text) == B_OK) {
				SetString(text);
				Invalidate(/*&fBoxRegion*/);
			}
			break;
		}

		case FONTSTYLE_CHANGED_MSG:
		{
			BMessage fontMessage;
			if (msg->FindMessage("_fontMessage", &fontMessage) != B_OK)
				return;

			const char* family;
			const char* style;
			if (fontMessage.FindString("_family", &family) != B_OK
				|| fontMessage.FindString("_style", &style) != B_OK)
				return;

			fFont.SetFamilyAndStyle(family, style);
			Invalidate();
			break;
		}

		case FONTFAMILY_CHANGED_MSG:
		{
			BMessage fontMessage;
			if (msg->FindMessage("_fontMessage", &fontMessage) != B_OK)
				return;

			const char* family;
			if (fontMessage.FindString("_family", &family) != B_OK)
				return;

			font_style style;
			if (get_font_style(const_cast<char*>(family), 0, &style) == B_OK) {
				fFont.SetFamilyAndStyle(family, style);
				Invalidate(/*&fBoxRegion*/);
			}
			break;
		}

		case FONTSIZE_MSG:
		{
			float size = 0.0;
			if (msg->FindFloat("_size", &size) == B_OK) {
				SetFontSize(size);
				Invalidate(/*&fBoxRegion*/);
			}
			break;
		}

		case FONTSHEAR_MSG:
		{
			float shear = 90.0;
			if (msg->FindFloat("_shear", &shear) == B_OK) {
				SetFontShear(shear);
				Invalidate(/*&fBoxRegion*/);
			 }
			break;
		}

		case ROTATION_MSG:
		{
			float rotation = 0.0;
			if (msg->FindFloat("_rotation", &rotation) == B_OK) {
				SetFontRotation(rotation);
				Invalidate(/*&fBoxRegion*/);
			 }
			break;
		}

		case SPACING_MSG:
		{
			float space = 0.0;
			if (msg->FindFloat("_spacing", &space) == B_OK) {
				SetSpacing(space);
				Invalidate(/*&fBoxRegion*/);
			 }
			break;
		}

		case OUTLINE_MSG:
		{
			int8 outline = 0;
			if (msg->FindInt8("_outline", &outline) == B_OK) {
				SetOutlineLevel(outline);
				Invalidate(/*&fBoxRegion*/);
			 }
			break;
		}

		case ALIASING_MSG:
		{
			bool aliased = false;
			if (msg->FindBool("_aliased", &aliased) == B_OK) {
				SetAntialiasing(aliased);
				Invalidate(/*&fBoxRegion*/);
			}
			break;
		}

		case DRAWINGMODE_CHANGED_MSG:
		{
			if (msg->FindInt32("_mode", (int32 *)&fDrawingMode) == B_OK) {
				Invalidate(/*&fBoxRegion*/);
				switch (fDrawingMode) {
					case B_OP_COPY:
						printf("Drawing mode: B_OP_COPY\n");
						break;
					case B_OP_OVER:
						printf("Drawing mode: B_OP_OVER\n");
						break;
					case B_OP_ERASE:
						printf("Drawing mode: B_OP_ERASE\n");
						break;
					case B_OP_INVERT:
						printf("Drawing mode: B_OP_INVERT\n");
						break;
					case B_OP_ADD:
						printf("Drawing mode: B_OP_ADD\n");
						break;
					case B_OP_SUBTRACT:
						printf("Drawing mode: B_OP_SUBTRACT\n");
						break;
					case B_OP_BLEND:
						printf("Drawing mode: B_OP_BLEND\n");
						break;
 					case B_OP_MIN:
						printf("Drawing mode: B_OP_MIN\n");
						break;
					case B_OP_MAX:
						printf("Drawing mode: B_OP_MAX\n");
						break;
					case B_OP_SELECT:
						printf("Drawing mode: B_OP_SELECT\n");
						break;
					case B_OP_ALPHA:
						printf("Drawing mode: B_OP_ALPHA\n");
						break;
					default:
						printf("Drawing mode: %d\n", fDrawingMode);
				}
			}
			break;
		}

		case BOUNDING_BOX_MSG:
		{
			bool boundingbox = false;
			if (msg->FindBool("_boundingbox", &boundingbox) == B_OK) {
				SetDrawBoundingBoxes(boundingbox);
				Invalidate(/*&fBoxRegion*/);
			}
			break;
		}

		default:
			BView::MessageReceived(msg);
			break;
	}
}


void
FontDemoView::SetString(BString string)
{
	fString = string;
	free(fShapes);
	_AddShapes(fString);
}


BString
FontDemoView::String() const
{
	return fString;
}


void
FontDemoView::SetFontSize(float size)
{
	fFont.SetSize(size);
}


void
FontDemoView::SetFontShear(float shear)
{
	fFont.SetShear(shear);
}


void
FontDemoView::SetFontRotation(float rotation)
{
	fFont.SetRotation(rotation);
}


void
FontDemoView::SetDrawBoundingBoxes(bool state)
{
	fBoundingBoxes = state;
}


void
FontDemoView::SetAntialiasing(bool state)
{
	fFont.SetFlags(state ? B_FORCE_ANTIALIASING : B_DISABLE_ANTIALIASING);
}


void
FontDemoView::SetSpacing(float space)
{
	fSpacing = space;
}


void
FontDemoView::SetOutlineLevel(int8 outline)
{
	fOutLineLevel = outline;
}


void
FontDemoView::_AddShapes(BString string)
{
	const size_t size = string.CountChars();
	fShapes = (BShape**)malloc(sizeof(BShape*) * size);

	for (size_t i = 0; i < size; i++) {
		fShapes[i] = new BShape();
	}
}