haiku/src/servers/app/server/Layer.cpp
haydentech bdfe7cf5d2 Minor cleanup of erroneous comments
git-svn-id: file:///srv/svn/repos/haiku/trunk/current@5837 a95241bf-73f2-0310-859d-f6bbb57e9c96
2003-12-30 22:41:50 +00:00

1274 lines
31 KiB
C++

//------------------------------------------------------------------------------
// Copyright (c) 2001-2002, OpenBeOS
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
// File Name: Layer.cpp
// Author: DarkWyrm <bpmagic@columbus.rr.com>
// Description: Class used for rendering to the frame buffer. One layer per
// view on screen and also for window decorators
//
//------------------------------------------------------------------------------
#include <OS.h>
#include <View.h>
#include <Message.h>
#include <AppDefs.h>
#include <string.h>
#include <stdio.h>
#include "Layer.h"
#include "RectUtils.h"
#include "ServerWindow.h"
#include "ServerApp.h"
#include "PortLink.h"
#include "ServerCursor.h"
#include "CursorManager.h"
#include "TokenHandler.h"
#include "RootLayer.h"
#include "DisplayDriver.h"
#include "Desktop.h"
#include "RGBColor.h"
//#define DEBUG_LAYER
#ifdef DEBUG_LAYER
# include <stdio.h>
# define STRACE(x) printf x
#else
# define STRACE(x) ;
#endif
/*!
\brief Constructor
\param frame Size and placement of the Layer
\param name Name of the layer
\param resize Resizing flags as defined in View.h
\param flags BView flags as defined in View.h
\param win ServerWindow to which the Layer belongs
*/
Layer::Layer(BRect frame, const char *name, int32 token, uint32 resize,
uint32 flags, ServerWindow *win)
{
// frame is in _parent coordinates
if(frame.IsValid())
_frame = frame;
else
// TODO: Decorator class should have a method witch returns the minimum frame width.
_frame.Set(0.0f, 0.0f, 5.0f, 5.0f);
_boundsLeftTop.Set( 0.0f, 0.0f );
_name = new BString(name);
// Layer does not start out as a part of the tree
_parent = NULL;
_uppersibling = NULL;
_lowersibling = NULL;
_topchild = NULL;
_bottomchild = NULL;
/* NOW all regions (_visible, _fullVisible, _full) are empty */
_flags = flags;
_resize_mode = resize;
_hidden = false;
_is_updating = false;
_level = 0;
_view_token = token;
_layerdata = new LayerData;
_serverwin = win;
_cursor = NULL;
fDriver = GetGfxDriver(ActiveScreen());
}
//! Destructor frees all allocated heap space
Layer::~Layer(void)
{
if(_name)
{
delete _name;
_name = NULL;
}
if(_layerdata)
{
delete _layerdata;
_layerdata = NULL;
}
if (clipToPicture)
{
delete clipToPicture;
clipToPicture = NULL;
// TODO: allocate and relase a ServerPicture Object.
}
}
/*!
\brief Adds a child to the back of the a layer's child stack.
\param layer The layer to add as a child
\param before Add the child in front of this layer
\param rebuild Flag to fully rebuild all visibility regions
*/
void Layer::AddChild(Layer *layer, Layer *before)
{
if( layer->_parent != NULL ) {
printf("ERROR: AddChild(): Layer already has a _parent\n");
return;
}
// attach layer to the tree structure
layer->_parent = this;
if( _bottomchild ){
layer->_uppersibling = _bottomchild;
_bottomchild->_lowersibling = layer;
}
else{
_topchild = layer;
}
_bottomchild = layer;
layer->_level = _level+1;
layer->RebuildFullRegion();
if ( !(layer->_hidden) ){
// _layer->_full.Frame() is the maximum(layer's PoV), yet minimum(parent's PoV)
// region to be rebuilt.
RebuildChildRegions( layer->_full.Frame(), layer );
// REDRAWING CODE:
// RebuildChildRegion gave us a valid visible region.
if (layer->_visible.CountRects() > 0){
layer->Invalidate( layer->_visible );
}
}
}
/*!
\brief Removes a layer from the child stack
\param layer The layer to remove
\param rebuild Flag to rebuild all visibility regions
*/
void Layer::RemoveChild(Layer *layer)
{
if( layer->_parent == NULL ){
printf("ERROR: RemoveChild(): Layer doesn't have a _parent\n");
return;
}
if( layer->_parent != this ){
printf("ERROR: RemoveChild(): Layer is not a child of this layer\n");
return;
}
// cache some things. The rebuilding/redrawing process will need those.
Layer* cachedUpperSibling = layer->_uppersibling;
// Take care of _parent
layer->_parent = NULL;
if( _topchild == layer )
_topchild = layer->_lowersibling;
if( _bottomchild == layer )
_bottomchild = layer->_uppersibling;
// Take care of siblings
if( layer->_uppersibling != NULL )
layer->_uppersibling->_lowersibling = layer->_lowersibling;
if( layer->_lowersibling != NULL )
layer->_lowersibling->_uppersibling = layer->_uppersibling;
layer->_uppersibling = NULL;
layer->_lowersibling = NULL;
// eliminate layer's full visible region
if ( !(layer->_hidden) )
{
bool invalidate = false;
BRect invalidRect;
if (layer->_fullVisible.CountRects() > 0){
invalidate = true;
invalidRect = layer->_fullVisible.Frame();
RebuildChildRegions( layer->_fullVisible.Frame(), cachedUpperSibling );
}
// REDRAWING CODE:
if (invalidate){
DoInvalidate( BRegion(invalidRect), cachedUpperSibling );
}
}
}
/*!
\brief Removes the layer from its parent's child stack
\param rebuild Flag to rebuild visibility regions
*/
void Layer::RemoveSelf()
{
// A Layer removes itself from the tree (duh)
if( _parent == NULL ){
printf("ERROR: RemoveSelf(): Layer doesn't have a _parent\n");
return;
}
_parent->RemoveChild(this);
}
/*!
\brief Finds the first child at a given point.
\param pt Point to look for a child
\return non-NULL if found, NULL if not
Find out which child gets hit if we click at a certain spot. Returns NULL
if there are no _visible children or if the click does not hit a child layer
*/
Layer* Layer::GetLayerAt(const BPoint &pt)
{
if (_visible.Contains(pt)){
return this;
}
if (_fullVisible.Contains(pt)){
Layer *lay = NULL;
for ( Layer* child = _bottomchild; child != NULL; child = child->_uppersibling ){
if ( (lay = child->GetLayerAt( pt )) )
return lay;
}
}
return NULL;
}
/*!
\brief Returns the size of the layer
\return the size of the layer
*/
BRect Layer::Bounds(void) const
{
BRect r(_frame);
r.OffsetTo( _boundsLeftTop );
return r;
}
/*!
\brief Returns the layer's size and position in its parent coordinates
\return The layer's size and position in its parent coordinates
*/
BRect Layer::Frame(void) const
{
return _frame;
}
/*!
\brief recursively deletes all children (and grandchildren, etc) of the layer
This is mostly used for server shutdown or deleting a workspace
*/
void Layer::PruneTree(void)
{
Layer *lay,
*nextlay;
lay = _topchild;
_topchild = NULL;
while(lay != NULL)
{
if(lay->_topchild != NULL) {
lay->PruneTree();
}
nextlay = lay->_lowersibling;
lay->_lowersibling = NULL;
delete lay;
lay = nextlay;
}
// Man, this thing is short. Elegant, ain't it? :P
}
/*!
\brief Finds a layer based on its token ID
\return non-NULL if found, NULL if not
*/
Layer* Layer::FindLayer(const int32 token)
{
// recursive search for a layer based on its view token
Layer *lay,
*trylay;
// Search child layers first
for(lay = _topchild; lay != NULL; lay = lay->_lowersibling)
{
if(lay->_view_token == token)
return lay;
}
// Hmmm... not in this layer's children. Try lower descendants
for(lay = _topchild; lay != NULL; lay = lay->_lowersibling)
{
trylay = lay->FindLayer(token);
if(trylay)
return trylay;
}
// Well, we got this far in the function, so apparently there is no match to be found
return NULL;
}
/*!
\brief Sets the layer's personal cursor. See BView::SetViewCursor
\return The cursor associated with this layer.
*/
void Layer::SetLayerCursor(ServerCursor *csr)
{
_cursor = csr;
}
/*!
\brief Returns the layer's personal cursor. See BView::SetViewCursor
\return The cursor associated with this layer.
*/
ServerCursor *Layer::GetLayerCursor(void) const
{
return _cursor;
}
/*!
\brief Hook function for handling pointer transitions, much like BView::MouseMoved
\param transit The type of event which occurred.
The default version of this function changes the cursor to the view's cursor, if there
is one. If there isn't one, the default cursor is chosen
*/
void Layer::MouseTransit(uint32 transit)
{
if(transit == B_ENTERED_VIEW)
{
if(_cursor)
cursormanager->SetCursor(_cursor->ID());
else
{
if(_serverwin)
_serverwin->GetApp()->SetAppCursor();
else
cursormanager->SetCursor(B_CURSOR_DEFAULT);
}
}
}
void Layer::DoInvalidate(const BRegion &reg, Layer *start){
//TODO: REMOVE this! For Test purposes only!
return;
if (_hidden || !(_fullVisible.Intersects(reg.Frame())) ){
printf("SERVER: WARNING: Layer(%s)::DoInvalidate() 1 \n\n", _name->String());
return;
}
// we're here! that means that our view is not hidden, HAS a valid '_fullVisible' region,
// AND, of course, it intersects the update region.
// redraw one of our regions if needed.
if ( _visible.CountRects() > 0 ){
BRegion iReg(_visible);
iReg.IntersectWith( &reg );
if ( iReg.CountRects() > 0 ){
if (_serverwin){
RequestClientUpdate( iReg.Frame() );
}
else{
RequestDraw( iReg.Frame() );
}
}
}
if (start == NULL){
printf("SERVER: WARNING: Layer(%s)::DoInvalidate() 2 \n\n", _name->String());
return;
}
// redraw parts of our children, if needed.
bool redraw = false;
// Redraw regions for children... if needed!
for(Layer *lay = _bottomchild; lay != NULL; lay = lay->_uppersibling)
{
// for layers in front of 'start' no redraw is needed.
// so avoid unnecessary CPU cycles.
if ( lay == start && redraw == false)
redraw = true;
if ( redraw && !(lay->_hidden) && (lay->_fullVisible.CountRects() > 0) ){
BRegion layReg(lay->_fullVisible);
layReg.IntersectWith( &reg );
if ( layReg.CountRects() > 0 ){
if (lay->_serverwin){
lay->RequestClientUpdate( layReg.Frame() );
}
else{
lay->RequestDraw( layReg.Frame() );
}
}
}
}
}
/*!
\brief Sets a region as invalid and, thus, needing to be drawn
\param The region to invalidate
All children of the layer also receive this call, so only 1 Invalidate call is
needed to set a section as invalid on the screen.
*/
void Layer::Invalidate(const BRegion& region)
{
if (_parent){
_parent->DoInvalidate(region, this);
}
else{
DoInvalidate(region, _topchild);
}
}
/*!
\brief Sets a rectangle as invalid and, thus, needing to be drawn
\param The rectangle to invalidate
All children of the layer also receive this call, so only 1 Invalidate call is
needed to set a section as invalid on the screen.
*/
void Layer::Invalidate(const BRect &rect)
{
Invalidate( BRegion(rect) );
}
/*!
\brief Sends update requests to client(BViews)
\param The rectangle into witch the client so draw
All children of the layer also receive this call.
*/
void Layer::RequestClientUpdate(const BRect &rect){
if (_hidden){
// this layer has nothing visible on screen, so bail out.
return;
}
// this method assumes _fullVisible.CountRects() is positive !!!!!!!!!!!!!
// clear the area in the low color
// only the visible area is cleared, because DisplayDriver does the clipping to it.
// draw background, *only IF* our view color is different to B_TRANSPARENT_COLOR!
if ( !(_layerdata->viewcolor == RGBColor(B_TRANSPARENT_COLOR)) ) {
RGBColor tempColor(B_TRANSPARENT_COLOR);
//_layerdata->lowcolor.SetColor( B_TRANSPARENT_COLOR );
fDriver->StrokeRect(rect, _layerdata->pensize, tempColor);
}
BMessage msg;
msg.what = _UPDATE_;
msg.AddInt32("_token", _view_token);
msg.AddRect("_rect", ConvertFromTop(rect) );
_serverwin->SendMessageToClient( &msg );
// This layer's BView counterpart will tell its children to redraw.
}
/*!
\brief Ask internal server layers to do their drawing
\param r The area that needs to be drawn. In SCREEN COORDINATES!!!
*/
void Layer::RequestDraw(const BRect &r)
{
if (_visible.CountRects() > 0){
RGBColor tempColor(B_TRANSPARENT_COLOR);
//_layerdata->lowcolor.SetColor( B_TRANSPARENT_COLOR );
fDriver->StrokeRect(r, _layerdata->pensize, tempColor);
// draw itself.
Draw(r);
}
// tell children to draw.
for (Layer *lay = _topchild; lay != NULL; lay = lay->_lowersibling){
if ( !(lay->_hidden) && r.Intersects(lay->_fullVisible.Frame()) ){
BRect newRect = (r & lay->_fullVisible.Frame());
lay->RequestDraw( newRect );
}
}
}
/*!
\brief Ask the layer to draw itself
\param r The area that needs to be drawn
*/
void Layer::Draw(const BRect &r)
{
// empty HOOK function.
}
//! Show the layer. Operates just like the BView call with the same name
void Layer::Show(void)
{
if( !_hidden )
return;
_hidden = false;
// rebuild layer visible region based on its parent's and those supplied by user
if (_parent){
_parent->RebuildChildRegions( _full.Frame(), this );
}
else{
RebuildRegions( _full.Frame() );
}
// REDRAWING CODE:
if (_fullVisible.CountRects() > 0)
Invalidate( _fullVisible );
}
//! Hide the layer. Operates just like the BView call with the same name
void Layer::Hide(void)
{
if ( _hidden )
return;
_hidden = true;
if (_fullVisible.CountRects() > 0){
BRegion cachedFullVisible = _fullVisible;
if (_parent){
_parent->RebuildChildRegions( _fullVisible.Frame(), this );
}
else{
RebuildRegions( _full.Frame() );
}
// REDRAWING CODE:
Invalidate( cachedFullVisible );
}
}
/*!
\brief Determines whether the layer is hidden or not
\return true if hidden, false if not.
*/
bool Layer::IsHidden(void) const
{
return _hidden;
}
/*!
\brief Counts the number of children the layer has
\return the number of children the layer has, not including grandchildren
*/
uint32 Layer::CountChildren(void) const
{
uint32 i=0;
Layer *lay=_topchild;
while(lay!=NULL)
{
lay=lay->_lowersibling;
i++;
}
return i;
}
void Layer::MoveRegionsBy(float x, float y){
// currently just the full region needs to be moved.
_full.OffsetBy(x, y);
for (Layer *lay = _topchild; lay != NULL; lay = lay->_lowersibling){
lay->MoveRegionsBy(x, y);
}
}
/*!
\brief Moves a layer in its parent coordinate space
\param x X offset
\param y Y offset
*/
void Layer::MoveBy(float x, float y)
{
BRegion oldFullVisible( _fullVisible );
// BPoint oldFullVisibleOrigin( _fullVisible.Frame().LeftTop() );
_frame.OffsetBy(x, y);
MoveRegionsBy(x, y);
if (_parent){
if ( !_hidden ){
// to clear the area occupied on its parent _visible
if (_fullVisible.CountRects() > 0){
_hidden = true;
_parent->RebuildChildRegions( _fullVisible.Frame(), this );
_hidden = false;
}
_parent->RebuildChildRegions( _full.Frame(), this );
}
}
else{
if ( !_hidden ) {
RebuildRegions( _full.Frame() );
}
}
// send a message to client if requested.
if(_flags & B_FRAME_EVENTS && _serverwin){
BMessage msg;
// no locking?
msg.what = B_VIEW_MOVED;
msg.AddInt64( "when", real_time_clock_usecs() );
msg.AddInt32( "_token", _view_token );
msg.AddPoint( "where", _frame.LeftTop() );
_serverwin->SendMessageToClient( &msg );
}
// REDRAWING CODE:
if ( !(_hidden) )
{
/* The region(on screen) that will be invalidated.
* It is composed by:
* the regions that were visible, and now they aren't +
* the regions that are now visible, and they were not visible before.
* (oldFullVisible - _fullVisible) + (_fullVisible - oldFullVisible)
*/
BRegion clipReg;
// first offset the old region so we can do the correct operations.
oldFullVisible.OffsetBy(x, y);
// + (oldFullVisible - _fullVisible)
if ( oldFullVisible.CountRects() > 0 ){
BRegion tempReg( oldFullVisible );
tempReg.Exclude( &_fullVisible );
if (tempReg.CountRects() > 0){
clipReg.Include( &tempReg );
}
}
// + (_fullVisible - oldFullVisible)
if ( _fullVisible.CountRects() > 0 ){
BRegion tempReg( _fullVisible );
tempReg.Exclude( &oldFullVisible );
if (tempReg.CountRects() > 0){
clipReg.Include( &tempReg );
}
}
// there is no point in redrawing what already is visible. So just copy
// on-screen pixels to layer's new location.
if ( (oldFullVisible.CountRects() > 0) && (_fullVisible.CountRects() > 0) ){
BRegion tempReg( oldFullVisible );
tempReg.IntersectWith( &_fullVisible );
if (tempReg.CountRects() > 0){
// TODO: when you have such a method in DisplayDriver/Clipper, uncomment!
//fDriver->CopyBits( &tempReg, oldFullVisibleOrigin, oldFullVisibleOrigin.OffsetByCopy(x,y) );
}
}
// invalidate 'clipReg' so we can see the results of this move.
if (clipReg.CountRects() > 0){
Invalidate( clipReg );
}
}
}
void Layer::ResizeRegionsBy(float x, float y){
_frame.right = _frame.right + x;
_frame.bottom = _frame.bottom + y;
RebuildFullRegion();
/* Send messages to BViews only if this Layer belongs to a
* ServerWindow object
*/
BMessage msg;
if( _serverwin )
{
msg.what = B_VIEW_RESIZED;
msg.AddInt64( "when", real_time_clock_usecs() );
msg.AddInt32( "_token", _view_token );
msg.AddFloat( "width", _frame.Width() );
msg.AddFloat( "height", _frame.Height() );
// no need for that... it's here because of backward compatibility
msg.AddPoint( "where", _frame.LeftTop() );
_serverwin->SendMessageToClient( &msg );
msg.MakeEmpty();
}
Layer *c = _topchild; //c = short for: current
if( c != NULL )
while( true ){
// action block
{
bool sendMovedToMsg = false;
bool sendResizedToMsg = false;
{
BRect newFrame = c->_frame;
uint32 rmask = c->_resize_mode;
if (rmask == B_FOLLOW_NONE)
rmask = B_FOLLOW_LEFT | B_FOLLOW_TOP;
// resize/move horizontaly
if (rmask & B_FOLLOW_LEFT){
// nothing to do
}
else if (rmask & B_FOLLOW_RIGHT){
newFrame.OffsetBy(x, 0.0f);
sendMovedToMsg = true;
}
else if (rmask & B_FOLLOW_LEFT_RIGHT){
newFrame.SetRightBottom( BPoint(newFrame.right + x, newFrame.bottom) );
sendResizedToMsg = true;
}
else if (rmask & B_FOLLOW_H_CENTER){
newFrame.OffsetBy(x/2, 0.0f);
sendMovedToMsg = true;
}
else { // illegal flag. Do nothing.
}
// resize/move verticaly
if (rmask & B_FOLLOW_TOP){
// nothing to do
}
else if (rmask & B_FOLLOW_BOTTOM){
newFrame.OffsetBy(0.0f, y);
sendMovedToMsg = true;
}
else if (rmask & B_FOLLOW_TOP_BOTTOM){
newFrame.SetRightBottom( BPoint(newFrame.right, newFrame.bottom + y) );
sendResizedToMsg = true;
}
else if (rmask & B_FOLLOW_V_CENTER){
newFrame.OffsetBy(0.0f, y/2);
sendMovedToMsg = true;
}
else { // illegal flag. Do nothing.
}
if (sendMovedToMsg && !sendResizedToMsg){
c->_full.OffsetBy( (newFrame.left - c->_frame.left),
(newFrame.top - c->_frame.top) );
}
c->_frame = newFrame;
if (sendResizedToMsg){
c->RebuildFullRegion();
}
}
// send message to client it requested (flags & B_FRAME_EVENTS)
if ( c->_serverwin ){
if ( sendMovedToMsg && (c->_flags & B_FRAME_EVENTS) ) {
msg.what = B_VIEW_MOVED;
msg.AddInt64( "when", real_time_clock_usecs() );
msg.AddInt32( "_token", c->_view_token );
msg.AddPoint( "where", c->_frame.LeftTop() );
c->_serverwin->SendMessageToClient( &msg );
msg.MakeEmpty();
}
if ( sendResizedToMsg && (c->_flags & B_FRAME_EVENTS) ){
msg.what = B_VIEW_RESIZED;
msg.AddInt64( "when", real_time_clock_usecs() );
msg.AddInt32( "_token", c->_view_token );
msg.AddFloat( "width", c->_frame.Width() );
msg.AddFloat( "height", c->_frame.Height() );
// no need for that... it's here because of backward compatibility
msg.AddPoint( "where", c->_frame.LeftTop() );
c->_serverwin->SendMessageToClient( &msg );
msg.MakeEmpty();
}
}
}
// tree parsing algorithm
// go deep
if( c->_topchild ){
c = c->_topchild;
}
// go right or up
else
// go right
if( c->_lowersibling ){
c = c->_lowersibling;
}
// go up
else{
while( !c->_parent->_lowersibling && c->_parent != this ){
c = c->_parent;
}
// that enough! We've reached this view.
if( c->_parent == this )
break;
c = c->_parent->_lowersibling;
}
}
}
/*!
\brief Resizes the layer.
\param x X offset
\param y Y offset
This resizes the layer itself and resizes any children based on their resize
flags.
*/
void Layer::ResizeBy(float x, float y)
{
BRegion oldFullVisible( _fullVisible );
ResizeRegionsBy(x, y);
if (_parent){
if ( !_hidden ){
_parent->RebuildChildRegions( _full.Frame(), this );
}
}
else{
if ( !_hidden ){
RebuildRegions( _full.Frame() );
}
}
// REDRAWING CODE:
if ( !(_hidden) )
{
/* The region(on screen) that will be invalidated.
* It is composed by:
* the regions that were visible, and now they aren't +
* the regions that are now visible, and they were not visible before.
* (oldFullVisible - _fullVisible) + (_fullVisible - oldFullVisible)
*/
BRegion clipReg;
// + (oldFullVisible - _fullVisible)
if ( oldFullVisible.CountRects() > 0 ){
BRegion tempReg( oldFullVisible );
tempReg.Exclude( &_fullVisible );
if (tempReg.CountRects() > 0){
clipReg.Include( &tempReg );
}
}
// + (_fullVisible - oldFullVisible)
if ( _fullVisible.CountRects() > 0 ){
BRegion tempReg( _fullVisible );
tempReg.Exclude( &oldFullVisible );
if (tempReg.CountRects() > 0){
clipReg.Include( &tempReg );
}
}
// invalidate 'clipReg' so we can see the results of this resize operation.
if (clipReg.CountRects() > 0){
Invalidate( clipReg );
}
}
}
void Layer::RebuildChildRegions( const BRect &r, Layer* startFrom ){
// just in case something goes wrong.
if ( _hidden ){
printf("\nSERVER PANIC: Layer(%s)::RebuildChildRegions() - This should NOT happen.\n\n", _name->String());
return;
}
// here is the actual start of this method. :-))
bool rebuild = false;
_visible = _fullVisible;
// Rebuild regions for children... if needed!
for(Layer *lay = _bottomchild; lay != NULL; lay = lay->_uppersibling)
{
// for layers in front of 'startLayer' no region rebuild is needed.
// so avoid unnecessary CPU cycles.
if ( lay == startFrom && rebuild == false)
rebuild = true;
if ( !(lay->_hidden) ){
if ( !rebuild ){
// do not rebuild, but exclude lay's FULL visible region from its parent v.r.
_visible.Exclude( &(lay->_fullVisible) );
}
else{
lay->RebuildRegions( r );
}
}
}
}
/*!
\brief Rebuilds visibility regions for this and child layers
\param include_children Flag to rebuild all children and subchildren
*/
void Layer::RebuildRegions( const BRect& r )
{
// if we're in the rebuild area, rebuild our v.r.
if ( _full.Intersects( r ) ){
_visible = _full;
if (_parent){
_visible.IntersectWith( &(_parent->_visible) );
// exclude from parent's visible area.
if ( !(_hidden) )
_parent->_visible.Exclude( &(_visible) );
}
_fullVisible = _visible;
}
else{
// our visible region will stay the same
// exclude our FULL visible region from parent's visible region.
if ( !(_hidden) && _parent )
_parent->_visible.Exclude( &(_fullVisible) );
// we're not in the rebuild area so our children's v.r.s are OK.
return;
}
// Rebuild regions for children...
for(Layer *lay = _bottomchild; lay != NULL; lay = lay->_uppersibling)
{
if ( !(lay->_hidden) ){
lay->RebuildRegions( r );
}
}
}
void Layer::RebuildFullRegion( ){
_full.Set( ConvertToTop( _frame ) );
LayerData *ld;
ld = _layerdata;
do{
// clip to user region
if ( ld->clippReg )
_full.IntersectWith( ld->clippReg );
} while( (ld = ld->prevState) );
// clip to user picture region
if ( clipToPicture )
if ( clipToPictureInverse ) {
_full.Exclude( clipToPicture );
}
else{
_full.IntersectWith( clipToPicture );
}
}
//! Prints all relevant layer data to stdout
void Layer::PrintToStream(void)
{
printf("-----------\nLayer %s\n",_name->String());
if(_parent)
printf("Parent: %s (%p)\n",_parent->_name->String(), _parent);
else
printf("Parent: NULL\n");
if(_uppersibling)
printf("Upper sibling: %s (%p)\n",_uppersibling->_name->String(), _uppersibling);
else
printf("Upper sibling: NULL\n");
if(_lowersibling)
printf("Lower sibling: %s (%p)\n",_lowersibling->_name->String(), _lowersibling);
else
printf("Lower sibling: NULL\n");
if(_topchild)
printf("Top child: %s (%p)\n",_topchild->_name->String(), _topchild);
else
printf("Top child: NULL\n");
if(_bottomchild)
printf("Bottom child: %s (%p)\n",_bottomchild->_name->String(), _bottomchild);
else
printf("Bottom child: NULL\n");
printf("Frame: "); _frame.PrintToStream();
printf("Token: %ld\nLevel: %ld\n",_view_token, _level);
printf("Hide count: %s\n",_hidden?"true":"false");
printf("Visible Areas: "); _visible.PrintToStream();
printf("Is updating = %s\n",(_is_updating)?"yes":"no");
}
//! Prints hierarchy data to stdout
void Layer::PrintNode(void)
{
printf("-----------\nLayer %s\n",_name->String());
if(_parent)
printf("Parent: %s (%p)\n",_parent->_name->String(), _parent);
else
printf("Parent: NULL\n");
if(_uppersibling)
printf("Upper sibling: %s (%p)\n",_uppersibling->_name->String(), _uppersibling);
else
printf("Upper sibling: NULL\n");
if(_lowersibling)
printf("Lower sibling: %s (%p)\n",_lowersibling->_name->String(), _lowersibling);
else
printf("Lower sibling: NULL\n");
if(_topchild)
printf("Top child: %s (%p)\n",_topchild->_name->String(), _topchild);
else
printf("Top child: NULL\n");
if(_bottomchild)
printf("Bottom child: %s (%p)\n",_bottomchild->_name->String(), _bottomchild);
else
printf("Bottom child: NULL\n");
printf("Visible Areas: "); _visible.PrintToStream();
}
//! Prints the tree structure starting from this layer
void Layer::PrintTree(){
int32 spaces = 2;
Layer *c = _topchild; //c = short for: current
printf( "'%s' - token: %ld\n", _name->String(), _view_token );
if( c != NULL )
while( true ){
// action block
{
for( int i = 0; i < spaces; i++)
printf(" ");
printf( "'%s' - token: %ld\n", c->_name->String(), c->_view_token );
}
// go deep
if( c->_topchild ){
c = c->_topchild;
spaces += 2;
}
// go right or up
else
// go right
if( c->_lowersibling ){
c = c->_lowersibling;
}
// go up
else{
while( !c->_parent->_lowersibling && c->_parent != this ){
c = c->_parent;
spaces -= 2;
}
// that enough! We've reached this view.
if( c->_parent == this )
break;
c = c->_parent->_lowersibling;
spaces -= 2;
}
}
}
/*!
\brief Converts the rectangle to the layer's parent coordinates
\param the rectangle to convert
\return the converted rectangle
*/
BRect Layer::ConvertToParent(BRect rect)
{
return (rect.OffsetByCopy(_frame.LeftTop()));
}
/*!
\brief Converts the region to the layer's parent coordinates
\param the region to convert
\return the converted region
*/
BRegion Layer::ConvertToParent(BRegion *reg)
{
BRegion newreg;
for(int32 i=0; i<reg->CountRects(); i++)
newreg.Include( (reg->RectAt(i)).OffsetByCopy(_frame.LeftTop()) );
return newreg;
}
/*!
\brief Converts the rectangle from the layer's parent coordinates
\param the rectangle to convert
\return the converted rectangle
*/
BRect Layer::ConvertFromParent(BRect rect)
{
return (rect.OffsetByCopy(_frame.left*-1,_frame.top*-1));
}
/*!
\brief Converts the region from the layer's parent coordinates
\param the region to convert
\return the converted region
*/
BRegion Layer::ConvertFromParent(BRegion *reg)
{
BRegion newreg;
for(int32 i=0; i<reg->CountRects();i++)
newreg.Include((reg->RectAt(i)).OffsetByCopy(_frame.left*-1,_frame.top*-1));
return newreg;
}
/*!
\brief Converts the region to screen coordinates
\param the region to convert
\return the converted region
*/
BRegion Layer::ConvertToTop(BRegion *reg)
{
BRegion newreg;
for(int32 i=0; i<reg->CountRects();i++)
newreg.Include(ConvertToTop(reg->RectAt(i)));
return newreg;
}
/*!
\brief Converts the rectangle to screen coordinates
\param the rectangle to convert
\return the converted rectangle
*/
BRect Layer::ConvertToTop(BRect rect)
{
if (_parent!=NULL)
return(_parent->ConvertToTop(rect.OffsetByCopy(_frame.LeftTop())) );
else
return(rect);
}
/*!
\brief Converts the region from screen coordinates
\param the region to convert
\return the converted region
*/
BRegion Layer::ConvertFromTop(BRegion *reg)
{
BRegion newreg;
for(int32 i=0; i<reg->CountRects();i++)
newreg.Include(ConvertFromTop(reg->RectAt(i)));
return newreg;
}
/*!
\brief Converts the rectangle from screen coordinates
\param the rectangle to convert
\return the converted rectangle
*/
BRect Layer::ConvertFromTop(BRect rect)
{
if (_parent!=NULL)
return(_parent->ConvertFromTop(rect.OffsetByCopy(_frame.LeftTop().x*-1,
_frame.LeftTop().y*-1)) );
else
return(rect);
}
/*!
\brief Makes the layer the backmost layer belonging to its parent
This function will do nothing if the Layer has no parent or no siblings. Region
rebuilding is not performed.
*/
void Layer::MakeTopChild(void)
{
// Handle redundant and pointless cases
if(!_parent || (!_uppersibling && !_lowersibling) || _parent->_topchild==this)
return;
// Pull ourselves out of the layer tree
if(_uppersibling)
_uppersibling->_lowersibling=_lowersibling;
if(_lowersibling)
_lowersibling->_uppersibling=_uppersibling;
// Set this layer's upper/lower sib pointers to appropriate values
_uppersibling=NULL;
_lowersibling=_parent->_topchild;
// move former top child down a layer
_lowersibling->_uppersibling=this;
_parent->_topchild=this;
}
/*!
\brief Makes the layer the frontmost layer belonging to its parent
This function will do nothing if the Layer has no parent or no siblings. Region
rebuilding is not performed.
*/
void Layer::MakeBottomChild(void)
{
// Handle redundant and pointless cases
if(!_parent || (!_uppersibling && !_lowersibling) || _parent->_bottomchild==this)
return;
// Pull ourselves out of the layer tree
if(_uppersibling)
_uppersibling->_lowersibling=_lowersibling;
if(_lowersibling)
_lowersibling->_uppersibling=_uppersibling;
// Set this layer's upper/lower sib pointers to appropriate values
_uppersibling=_parent->_bottomchild;
_lowersibling=NULL;
// move former bottom child up a layer
_uppersibling->_lowersibling=this;
_parent->_bottomchild=this;
}
/*
@log
* added 2 new methods - DoMoveTo and DoResizeTo. They move/resize the frame rectangle of Layer class.
In DoResizeTo() I added some code for autoresizing(based on BView's resizeMask parameter) of children. Still, the effective code for resizing need to be written. :-) I could do that, but other things have greater priority. :-)
*/