173a2ffbaSStephan Aßmus/*
273a2ffbaSStephan Aßmus * Copyright 2006, Haiku. All rights reserved.
373a2ffbaSStephan Aßmus * Distributed under the terms of the MIT License.
473a2ffbaSStephan Aßmus *
573a2ffbaSStephan Aßmus * Authors:
673a2ffbaSStephan Aßmus *		Stephan A��mus <superstippi@gmx.de>
773a2ffbaSStephan Aßmus */
873a2ffbaSStephan Aßmus
973a2ffbaSStephan Aßmus#include "Canvas.h"
1073a2ffbaSStephan Aßmus
1173a2ffbaSStephan Aßmus#include <new>
1273a2ffbaSStephan Aßmus#include <stdio.h>
1373a2ffbaSStephan Aßmus
1473a2ffbaSStephan Aßmus#include <Bitmap.h>
1573a2ffbaSStephan Aßmus#include <Entry.h>
1673a2ffbaSStephan Aßmus#include <Message.h>
1773a2ffbaSStephan Aßmus
1873a2ffbaSStephan Aßmus#include "Layer.h"
1973a2ffbaSStephan Aßmus
2073a2ffbaSStephan Aßmususing std::nothrow;
2173a2ffbaSStephan Aßmus
2273a2ffbaSStephan Aßmus// constructor
2373a2ffbaSStephan AßmusCanvas::Canvas(BRect frame)
2473a2ffbaSStephan Aßmus	: BList(10),
2573a2ffbaSStephan Aßmus	  fBounds(frame)
2673a2ffbaSStephan Aßmus{
2773a2ffbaSStephan Aßmus}
2873a2ffbaSStephan Aßmus
2973a2ffbaSStephan Aßmus// destructor
3073a2ffbaSStephan AßmusCanvas::~Canvas()
3173a2ffbaSStephan Aßmus{
3273a2ffbaSStephan Aßmus	MakeEmpty();
3373a2ffbaSStephan Aßmus}
3473a2ffbaSStephan Aßmus
3573a2ffbaSStephan Aßmus// IsValid
3673a2ffbaSStephan Aßmusbool
3773a2ffbaSStephan AßmusCanvas::IsValid() const
3873a2ffbaSStephan Aßmus{
3973a2ffbaSStephan Aßmus	return fBounds.IsValid();
4073a2ffbaSStephan Aßmus}
4173a2ffbaSStephan Aßmus
4273a2ffbaSStephan Aßmus// MakeEmpty
4373a2ffbaSStephan Aßmusvoid
4473a2ffbaSStephan AßmusCanvas::MakeEmpty()
4573a2ffbaSStephan Aßmus{
4673a2ffbaSStephan Aßmus	int32 count = CountLayers();
4773a2ffbaSStephan Aßmus	for (int32 i = 0; i < count; i++)
4873a2ffbaSStephan Aßmus		delete LayerAtFast(i);
4973a2ffbaSStephan Aßmus	BList::MakeEmpty();
5073a2ffbaSStephan Aßmus}
5173a2ffbaSStephan Aßmus
5273a2ffbaSStephan Aßmus// AddLayer
5373a2ffbaSStephan Aßmusbool
5473a2ffbaSStephan AßmusCanvas::AddLayer(Layer* layer)
5573a2ffbaSStephan Aßmus{
5673a2ffbaSStephan Aßmus	return AddLayer(layer, CountLayers());
5773a2ffbaSStephan Aßmus}
5873a2ffbaSStephan Aßmus
5973a2ffbaSStephan Aßmus// AddLayer
6073a2ffbaSStephan Aßmusbool
6173a2ffbaSStephan AßmusCanvas::AddLayer(Layer* layer, int32 index)
6273a2ffbaSStephan Aßmus{
6373a2ffbaSStephan Aßmus	return layer && AddItem((void*)layer, index);
6473a2ffbaSStephan Aßmus}
6573a2ffbaSStephan Aßmus
6673a2ffbaSStephan Aßmus// RemoveLayer
6773a2ffbaSStephan AßmusLayer*
6873a2ffbaSStephan AßmusCanvas::RemoveLayer(int32 index)
6973a2ffbaSStephan Aßmus{
7073a2ffbaSStephan Aßmus	return (Layer*)RemoveItem(index);
7173a2ffbaSStephan Aßmus}
7273a2ffbaSStephan Aßmus
7373a2ffbaSStephan Aßmus// RemoveLayer
7473a2ffbaSStephan Aßmusbool
7573a2ffbaSStephan AßmusCanvas::RemoveLayer(Layer* layer)
7673a2ffbaSStephan Aßmus{
7773a2ffbaSStephan Aßmus	return RemoveItem((void*)layer);
7873a2ffbaSStephan Aßmus}
7973a2ffbaSStephan Aßmus
8073a2ffbaSStephan Aßmus// LayerAt
8173a2ffbaSStephan AßmusLayer*
8273a2ffbaSStephan AßmusCanvas::LayerAt(int32 index) const
8373a2ffbaSStephan Aßmus{
8473a2ffbaSStephan Aßmus	return (Layer*)ItemAt(index);
8573a2ffbaSStephan Aßmus}
8673a2ffbaSStephan Aßmus
8773a2ffbaSStephan Aßmus// LayerAtFast
8873a2ffbaSStephan AßmusLayer*
8973a2ffbaSStephan AßmusCanvas::LayerAtFast(int32 index) const
9073a2ffbaSStephan Aßmus{
9173a2ffbaSStephan Aßmus	return (Layer*)ItemAtFast(index);
9273a2ffbaSStephan Aßmus}
9373a2ffbaSStephan Aßmus
9473a2ffbaSStephan Aßmus// IndexOf
9573a2ffbaSStephan Aßmusint32
9673a2ffbaSStephan AßmusCanvas::IndexOf(Layer* layer) const
9773a2ffbaSStephan Aßmus{
9873a2ffbaSStephan Aßmus	return BList::IndexOf((void*)layer);
9973a2ffbaSStephan Aßmus}
10073a2ffbaSStephan Aßmus
10173a2ffbaSStephan Aßmus// CountLayers
10273a2ffbaSStephan Aßmusint32
10373a2ffbaSStephan AßmusCanvas::CountLayers() const
10473a2ffbaSStephan Aßmus{
10573a2ffbaSStephan Aßmus	return CountItems();
10673a2ffbaSStephan Aßmus}
10773a2ffbaSStephan Aßmus
10873a2ffbaSStephan Aßmus// HasLayer
10973a2ffbaSStephan Aßmusbool
11073a2ffbaSStephan AßmusCanvas::HasLayer(Layer* layer) const
11173a2ffbaSStephan Aßmus{
11273a2ffbaSStephan Aßmus	return HasItem((void*)layer);
11373a2ffbaSStephan Aßmus}
11473a2ffbaSStephan Aßmus
11573a2ffbaSStephan Aßmus// SetBounds
11673a2ffbaSStephan Aßmusvoid
11773a2ffbaSStephan AßmusCanvas::SetBounds(BRect bounds)
11873a2ffbaSStephan Aßmus{
11973a2ffbaSStephan Aßmus	if (bounds.IsValid())
12073a2ffbaSStephan Aßmus		fBounds = bounds;
12173a2ffbaSStephan Aßmus}
12273a2ffbaSStephan Aßmus
12373a2ffbaSStephan Aßmus// Bounds
12473a2ffbaSStephan AßmusBRect
12573a2ffbaSStephan AßmusCanvas::Bounds() const
12673a2ffbaSStephan Aßmus{
12773a2ffbaSStephan Aßmus	return fBounds;
12873a2ffbaSStephan Aßmus}
12973a2ffbaSStephan Aßmus
13073a2ffbaSStephan Aßmus// Compose
13173a2ffbaSStephan Aßmusvoid
13273a2ffbaSStephan AßmusCanvas::Compose(BBitmap* into, BRect area) const
13373a2ffbaSStephan Aßmus{
13473a2ffbaSStephan Aßmus	if (into && into->IsValid()
13573a2ffbaSStephan Aßmus		&& area.IsValid() && area.Intersects(into->Bounds())) {
13673a2ffbaSStephan Aßmus		area = area & into->Bounds();
13773a2ffbaSStephan Aßmus		int32 count = CountLayers();
13873a2ffbaSStephan Aßmus		for (int32 i = count - 1; Layer* layer = LayerAt(i); i--) {
13973a2ffbaSStephan Aßmus			layer->Compose(into, area);
14073a2ffbaSStephan Aßmus		}
14173a2ffbaSStephan Aßmus	}
14273a2ffbaSStephan Aßmus}
14373a2ffbaSStephan Aßmus
14473a2ffbaSStephan Aßmus// Bitmap
14573a2ffbaSStephan AßmusBBitmap*
14673a2ffbaSStephan AßmusCanvas::Bitmap() const
14773a2ffbaSStephan Aßmus{
14873a2ffbaSStephan Aßmus	BBitmap* bitmap = new BBitmap(fBounds, 0, B_RGBA32);
14973a2ffbaSStephan Aßmus	if (!bitmap->IsValid()) {
15073a2ffbaSStephan Aßmus		delete bitmap;
15173a2ffbaSStephan Aßmus		return NULL;
15273a2ffbaSStephan Aßmus	}
15373a2ffbaSStephan Aßmus
15473a2ffbaSStephan Aßmus	// this bitmap is uninitialized, clear to black/fully transparent
15573a2ffbaSStephan Aßmus	memset(bitmap->Bits(), 0, bitmap->BitsLength());
15673a2ffbaSStephan Aßmus	Compose(bitmap, fBounds);
15773a2ffbaSStephan Aßmus	// remove image data where alpha = 0 to improve compression later on
15873a2ffbaSStephan Aßmus	uint8* bits = (uint8*)bitmap->Bits();
15973a2ffbaSStephan Aßmus	uint32 bpr = bitmap->BytesPerRow();
16073a2ffbaSStephan Aßmus	uint32 width = bitmap->Bounds().IntegerWidth() + 1;
16173a2ffbaSStephan Aßmus	uint32 height = bitmap->Bounds().IntegerHeight() + 1;
16273a2ffbaSStephan Aßmus	while (height > 0) {
16373a2ffbaSStephan Aßmus		uint8* bitsHandle = bits;
16473a2ffbaSStephan Aßmus		for (uint32 x = 0; x < width; x++) {
16573a2ffbaSStephan Aßmus			if (!bitsHandle[3]) {
16673a2ffbaSStephan Aßmus				bitsHandle[0] = 0;
16773a2ffbaSStephan Aßmus				bitsHandle[1] = 0;
16873a2ffbaSStephan Aßmus				bitsHandle[2] = 0;
16973a2ffbaSStephan Aßmus			}
17073a2ffbaSStephan Aßmus			bitsHandle += 4;
17173a2ffbaSStephan Aßmus		}
17273a2ffbaSStephan Aßmus		bits += bpr;
17373a2ffbaSStephan Aßmus		height--;
17473a2ffbaSStephan Aßmus	}
17573a2ffbaSStephan Aßmus
17673a2ffbaSStephan Aßmus	return bitmap;
17773a2ffbaSStephan Aßmus}
17873a2ffbaSStephan Aßmus
17973a2ffbaSStephan Aßmus
18073a2ffbaSStephan Aßmus
18173a2ffbaSStephan Aßmusstatic const char*	LAYER_KEY			= "layer";
18273a2ffbaSStephan Aßmusstatic const char*	BOUNDS_KEY			= "bounds";
18373a2ffbaSStephan Aßmus
18473a2ffbaSStephan Aßmus// Unarchive
18573a2ffbaSStephan Aßmusstatus_t
18673a2ffbaSStephan AßmusCanvas::Unarchive(const BMessage* archive)
18773a2ffbaSStephan Aßmus{
18873a2ffbaSStephan Aßmus	if (!archive)
18973a2ffbaSStephan Aßmus		return B_BAD_VALUE;
19073a2ffbaSStephan Aßmus
19173a2ffbaSStephan Aßmus	// restore bounds
19273a2ffbaSStephan Aßmus	BRect bounds;
19373a2ffbaSStephan Aßmus	if (archive->FindRect(BOUNDS_KEY, &bounds) < B_OK)
19473a2ffbaSStephan Aßmus		return B_ERROR;
19573a2ffbaSStephan Aßmus
19673a2ffbaSStephan Aßmus	fBounds = bounds;
19773a2ffbaSStephan Aßmus	// restore each layer
19873a2ffbaSStephan Aßmus	BMessage layerMessage;
19973a2ffbaSStephan Aßmus	for (int32 i = 0;
20073a2ffbaSStephan Aßmus		 archive->FindMessage(LAYER_KEY, i, &layerMessage) == B_OK;
20173a2ffbaSStephan Aßmus		 i++) {
20273a2ffbaSStephan Aßmus
20373a2ffbaSStephan Aßmus		Layer* layer = new (nothrow) Layer();
20473a2ffbaSStephan Aßmus		if (!layer || layer->Unarchive(&layerMessage) < B_OK
20573a2ffbaSStephan Aßmus			|| !AddLayer(layer)) {
20673a2ffbaSStephan Aßmus			delete layer;
20773a2ffbaSStephan Aßmus			return B_NO_MEMORY;
20873a2ffbaSStephan Aßmus		}
20973a2ffbaSStephan Aßmus	}
21073a2ffbaSStephan Aßmus
21173a2ffbaSStephan Aßmus	return B_OK;
21273a2ffbaSStephan Aßmus}
21373a2ffbaSStephan Aßmus
214