#include <OS.h>
#include <Region.h>
#include <Rect.h>
#include <stdio.h>
#include <strings.h>
#include <Window.h>
#include "Layer.h"
#include "MyView.h"
extern BWindow* wind;
Layer::Layer(BRect frame, const char* name, uint32 rm, uint32 flags, rgb_color c)
{
fFrame = frame;
fOrigin.Set(0.0f, 0.0f);
fResizeMode = rm;
fFlags = flags;
fColor = c;
fBottom = NULL;
fUpper = NULL;
fLower = NULL;
fTop = NULL;
fParent = NULL;
fView = NULL;
fCurrent = NULL;
fHidden = false;
strcpy(fName, name);
}
Layer::~Layer()
{
Layer *c = fBottom;
Layer *toast;
while (c) {
toast = c;
c = c->fUpper;
delete toast;
}
}
void
Layer::ConvertToScreen2(BRect* rect) const
{
if (GetRootLayer())
if (fParent) {
rect->OffsetBy(-fOrigin.x, -fOrigin.y);
rect->OffsetBy(fFrame.left, fFrame.top);
fParent->ConvertToScreen2(rect);
}
}
void
Layer::ConvertToScreen2(BRegion* reg) const
{
if (GetRootLayer())
if (fParent) {
reg->OffsetBy(-fOrigin.x, -fOrigin.y);
reg->OffsetBy(fFrame.left, fFrame.top);
fParent->ConvertToScreen2(reg);
}
}
MyView*
Layer::GetRootLayer() const
{
if (fView)
return fView;
else
if (fParent)
return fParent->GetRootLayer();
else
return NULL;
}
Layer*
Layer::BottomChild() const
{
fCurrent = fBottom;
return fCurrent;
}
Layer*
Layer::TopChild() const
{
fCurrent = fTop;
return fCurrent;
}
Layer*
Layer::UpperSibling() const
{
fCurrent = fCurrent->fUpper;
return fCurrent;
}
Layer*
Layer::LowerSibling() const
{
fCurrent = fCurrent->fLower;
return fCurrent;
}
void
Layer::AddLayer(Layer* layer)
{
if( layer->fParent != NULL ) {
printf("ERROR: Layer already has a parent\n");
return;
}
layer->fParent = this;
if (!fBottom) {
fBottom = layer;
fTop = layer;
return;
}
fBottom->fLower = layer;
layer->fUpper = fBottom;
fBottom = layer;
}
bool
Layer::RemLayer(Layer* layer)
{
if(!layer->fParent || layer->fParent != this) {
printf("ERROR: Rem: Layer doesn't have a fParent or !=this\n");
return false;
}
layer->fParent = NULL;
if(fTop == layer)
fTop = layer->fLower;
if(fBottom == layer )
fBottom = layer->fUpper;
if(layer->fUpper != NULL)
layer->fUpper->fLower = layer->fLower;
if(layer->fLower != NULL)
layer->fLower->fUpper = layer->fUpper;
layer->fUpper = NULL;
layer->fLower = NULL;
layer->clear_visible_regions();
return true;
}
bool
Layer::IsHidden() const
{
if (fHidden)
return true;
if (fView)
return false;
if (fParent)
return fParent->IsHidden();
return fHidden;
}
void
Layer::Hide()
{
fHidden = true;
if (fParent && !fParent->IsHidden() && GetRootLayer()) {
BRegion invalid(fFullVisible);
clear_visible_regions();
if (invalid.Frame().IsValid())
fParent->Invalidate(invalid, this);
}
}
void
Layer::Show()
{
fHidden = false;
if (fParent && !fParent->IsHidden() && GetRootLayer()) {
BRegion invalid;
get_user_regions(invalid);
if (invalid.CountRects() > 0)
fParent->Invalidate(invalid, this);
}
}
void
Layer::Invalidate(const BRegion &invalid, const Layer *startFrom)
{
BRegion localVisible(fFullVisible);
localVisible.IntersectWith(&invalid);
rebuild_visible_regions(invalid, localVisible,
startFrom? startFrom: BottomChild());
GetRootLayer()->fRedrawReg.Include(&localVisible);
GetRootLayer()->RequestRedraw();
}
inline void
Layer::resize_layer_frame_by(float x, float y)
{
uint16 rm = fResizeMode & 0x0000FFFF;
BRect newFrame = fFrame;
if ((rm & 0x0F00U) == _VIEW_LEFT_ << 8)
newFrame.left += 0.0f;
else if ((rm & 0x0F00U) == _VIEW_RIGHT_ << 8)
newFrame.left += x;
else if ((rm & 0x0F00U) == _VIEW_CENTER_ << 8)
newFrame.left += x/2;
if ((rm & 0x000FU) == _VIEW_LEFT_)
newFrame.right += 0.0f;
else if ((rm & 0x000FU) == _VIEW_RIGHT_)
newFrame.right += x;
else if ((rm & 0x000FU) == _VIEW_CENTER_)
newFrame.right += x/2;
if ((rm & 0xF000U) == _VIEW_TOP_ << 12)
newFrame.top += 0.0f;
else if ((rm & 0xF000U) == _VIEW_BOTTOM_ << 12)
newFrame.top += y;
else if ((rm & 0xF000U) == _VIEW_CENTER_ << 12)
newFrame.top += y/2;
if ((rm & 0x00F0U) == _VIEW_TOP_ << 4)
newFrame.bottom += 0.0f;
else if ((rm & 0x00F0U) == _VIEW_BOTTOM_ << 4)
newFrame.bottom += y;
else if ((rm & 0x00F0U) == _VIEW_CENTER_ << 4)
newFrame.bottom += y/2;
if (newFrame != fFrame) {
float dx, dy;
dx = newFrame.Width() - fFrame.Width();
dy = newFrame.Height() - fFrame.Height();
fFrame = newFrame;
if (dx != 0.0f || dy != 0.0f) {
ResizedByHook(dx, dy, true);
for (Layer *lay = BottomChild(); lay; lay = UpperSibling())
lay->resize_layer_frame_by(dx, dy);
}
else
MovedByHook(dx, dy);
}
}
inline void
Layer::rezize_layer_redraw_more(BRegion ®, float dx, float dy)
{
if (dx == 0 && dy == 0)
return;
for (Layer *lay = BottomChild(); lay; lay = UpperSibling()) {
uint16 rm = lay->fResizeMode & 0x0000FFFF;
if ((rm & 0x0F0F) == (uint16)B_FOLLOW_LEFT_RIGHT || (rm & 0xF0F0) == (uint16)B_FOLLOW_TOP_BOTTOM) {
BRect oldBounds(lay->Bounds());
if ((rm & 0x0F0F) == (uint16)B_FOLLOW_LEFT_RIGHT)
oldBounds.right -=dx;
if ((rm & 0xF0F0) == (uint16)B_FOLLOW_TOP_BOTTOM)
oldBounds.bottom -=dy;
BRegion regZ(lay->Bounds());
regZ.Include(oldBounds);
regZ.Exclude(oldBounds&lay->Bounds());
lay->ConvertToScreen2(®Z);
regZ.IntersectWith(&fFullVisible);
reg.Include(®Z);
lay->rezize_layer_redraw_more(reg,
(rm & 0x0F0F) == (uint16)B_FOLLOW_LEFT_RIGHT? dx: 0,
(rm & 0xF0F0) == (uint16)B_FOLLOW_TOP_BOTTOM? dy: 0);
}
else
if (((rm & 0x0F0F) == (uint16)B_FOLLOW_RIGHT && dx != 0) ||
((rm & 0x0F0F) == (uint16)B_FOLLOW_H_CENTER && dx != 0) ||
((rm & 0xF0F0) == (uint16)B_FOLLOW_BOTTOM && dy != 0)||
((rm & 0xF0F0) == (uint16)B_FOLLOW_V_CENTER && dy != 0))
{
reg.Include(&lay->fFullVisible);
}
}
}
inline void
Layer::resize_layer_full_update_on_resize(BRegion ®, float dx, float dy)
{
if (dx == 0 && dy == 0)
return;
for (Layer *lay = BottomChild(); lay; lay = UpperSibling()) {
uint16 rm = lay->fResizeMode & 0x0000FFFF;
if ((rm & 0x0F0F) == (uint16)B_FOLLOW_LEFT_RIGHT || (rm & 0xF0F0) == (uint16)B_FOLLOW_TOP_BOTTOM) {
if (lay->fFlags & B_FULL_UPDATE_ON_RESIZE && lay->fVisible.CountRects() > 0)
reg.Include(&lay->fVisible);
lay->resize_layer_full_update_on_resize(reg,
(rm & 0x0F0F) == (uint16)B_FOLLOW_LEFT_RIGHT? dx: 0,
(rm & 0xF0F0) == (uint16)B_FOLLOW_TOP_BOTTOM? dy: 0);
}
}
}
void
Layer::ResizeBy(float dx, float dy)
{
fFrame.Set(fFrame.left, fFrame.top, fFrame.right+dx, fFrame.bottom+dy);
for (Layer *lay = BottomChild(); lay; lay = UpperSibling())
lay->resize_layer_frame_by(dx, dy);
if (dx != 0.0f || dy != 0.0f)
ResizedByHook(dx, dy, false);
if (!IsHidden() && GetRootLayer()) {
BRegion oldFullVisible(fFullVisible);
BRegion oldVisible(fVisible);
BRegion redrawMore;
rezize_layer_redraw_more(redrawMore, dx, dy);
BRegion invalid;
get_user_regions(invalid);
invalid.Include(&fFullVisible);
clear_visible_regions();
fParent->RebuildVisibleRegions(invalid, this);
BRegion redrawReg(fFullVisible);
redrawReg.Exclude(&oldFullVisible);
BRegion redrawReg2(oldFullVisible);
redrawReg2.Exclude(&fFullVisible);
redrawReg.Include(&redrawReg2);
redrawReg.Include(&redrawMore);
rezize_layer_redraw_more(redrawReg, dx, dy);
GetRootLayer()->fRedrawReg.Include(&redrawReg);
if (fFlags & B_FULL_UPDATE_ON_RESIZE && fVisible.Frame().IsValid()) {
resize_layer_full_update_on_resize(GetRootLayer()->fRedrawReg, dx, dy);
GetRootLayer()->fRedrawReg.Include(&fVisible);
GetRootLayer()->fRedrawReg.Include(&oldVisible);
}
GetRootLayer()->RequestRedraw();
}
}
void Layer::MoveBy(float dx, float dy)
{
if (dx == 0.0f && dy == 0.0f)
return;
fFrame.OffsetBy(dx, dy);
MovedByHook(dx, dy);
if (!IsHidden() && GetRootLayer()) {
BRegion oldFullVisible(fFullVisible);
BRegion invalid;
get_user_regions(invalid);
invalid.Include(&fFullVisible);
clear_visible_regions();
fParent->RebuildVisibleRegions(invalid, this);
BRegion redrawReg(fFullVisible);
redrawReg.Include(&oldFullVisible);
oldFullVisible.OffsetBy(dx, dy);
redrawReg.Exclude(&oldFullVisible);
oldFullVisible.IntersectWith(&fFullVisible);
oldFullVisible.OffsetBy(-dx, -dy);
GetRootLayer()->CopyRegion(&oldFullVisible, dx, dy);
GetRootLayer()->fRedrawReg.Include(&redrawReg);
GetRootLayer()->RequestRedraw();
}
}
void
Layer::ScrollBy(float dx, float dy)
{
fOrigin.Set(fOrigin.x + dx, fOrigin.y + dy);
if (!IsHidden() && GetRootLayer()) {
BRegion invalid(fFullVisible);
clear_visible_regions();
rebuild_visible_regions(invalid, invalid, BottomChild());
BRegion redrawReg(fFullVisible);
invalid.OffsetBy(dx, dy);
invalid.IntersectWith(&fFullVisible);
GetRootLayer()->CopyRegion(&invalid, -dx, -dy);
invalid.OffsetBy(-dx, -dy);
redrawReg.Exclude(&invalid);
GetRootLayer()->fRedrawReg.Include(&redrawReg);
GetRootLayer()->RequestRedraw();
}
if (dx != 0.0f || dy != 0.0f)
ScrolledByHook(dx, dy);
}
void
Layer::GetWantedRegion(BRegion ®)
{
get_user_regions(reg);
}
void
Layer::get_user_regions(BRegion ®)
{
BRect screenFrame(Bounds());
ConvertToScreen2(&screenFrame);
reg.Set(screenFrame);
wind->Lock();
BRegion screenReg(GetRootLayer()->Bounds());
wind->Unlock();
reg.IntersectWith(&screenReg);
}
void
Layer::RebuildVisibleRegions(const BRegion &invalid, const Layer *startFrom)
{
BRegion localVisible(fFullVisible);
localVisible.IntersectWith(&invalid);
rebuild_visible_regions(invalid, localVisible, startFrom);
}
void
Layer::rebuild_visible_regions(const BRegion &invalid,
const BRegion &parentLocalVisible,
const Layer *startFrom)
{
if (fHidden)
return;
if (!parentLocalVisible.Frame().IsValid() && !(fFullVisible.CountRects() > 0))
return;
bool fullRebuild = false;
BRegion common;
get_user_regions(common);
common.IntersectWith(&invalid);
if (!common.CountRects() > 0)
return;
common.IntersectWith(&parentLocalVisible);
fFullVisible.Exclude(&invalid);
fVisible.Exclude(&invalid);
fFullVisible.Include(&common);
BRegion unalteredVisible(common);
bool altered = alter_visible_for_children(common);
for (Layer *lay = BottomChild(); lay; lay = UpperSibling()) {
if (lay == startFrom)
fullRebuild = true;
if (fullRebuild)
lay->rebuild_visible_regions(invalid, common, lay->BottomChild());
common.Exclude(&lay->fFullVisible);
if (altered)
unalteredVisible.Exclude(&lay->fFullVisible);
}
if (altered)
fVisible.Include(&unalteredVisible);
else
fVisible.Include(&common);
}
bool
Layer::alter_visible_for_children(BRegion ®)
{
return false;
}
void
Layer::clear_visible_regions()
{
fVisible.MakeEmpty();
fFullVisible.MakeEmpty();
for (Layer *child = BottomChild(); child; child = UpperSibling())
child->clear_visible_regions();
}
void
Layer::PrintToStream() const
{
printf("-> %s\n", fName);
fVisible.PrintToStream();
fFullVisible.PrintToStream();
for (Layer *child = BottomChild(); child; child = UpperSibling())
child->PrintToStream();
}