gtbase.cpp

来自「开放源码的编译器open watcom 1.6.0版的源代码」· C++ 代码 · 共 1,630 行 · 第 1/4 页

CPP
1,630
字号
/****************************************************************************
*
*                            Open Watcom Project
*
*    Portions Copyright (c) 1983-2002 Sybase, Inc. All Rights Reserved.
*
*  ========================================================================
*
*    This file contains Original Code and/or Modifications of Original
*    Code as defined in and that are subject to the Sybase Open Watcom
*    Public License version 1.0 (the 'License'). You may not use this file
*    except in compliance with the License. BY USING THIS FILE YOU AGREE TO
*    ALL TERMS AND CONDITIONS OF THE LICENSE. A copy of the License is
*    provided with the Original Code and Modifications, and is also
*    available at www.sybase.com/developer/opensource.
*
*    The Original Code and all software distributed under the License are
*    distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
*    EXPRESS OR IMPLIED, AND SYBASE AND ALL CONTRIBUTORS HEREBY DISCLAIM
*    ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF
*    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR
*    NON-INFRINGEMENT. Please see the License for the specific language
*    governing rights and limitations under the License.
*
*  ========================================================================
*
* Description:  WHEN YOU FIGURE OUT WHAT THIS FILE DOES, PLEASE
*               DESCRIBE IT HERE!
*
****************************************************************************/


/*
 * defines TreeWindow, TreeNode, TreeRoot and TreePtr, base classes used for
 * graphic trees. TreeNode and TreeWindow are abstract base classes.
 */

#include <wmsgdlg.hpp>

#include "assure.h"
#include "symbol.h"
#include "gtbase.h"
#include "gtring.h"
#include "gtwin.h"
#include "gtedges.h"
#include "screendv.h"

const NodeBuffer = 2;
const sibSep = 10;
const edgeStub = 5;
const childSep = 50;

//////////////////////////// TreePtr ///////////////////////////////

/* store an edge in the tree.  the minimum stored in this base class
 * is a from node (lower in vertical, to right in horizontal graphs),
 * and a to node (higher in vertical, to left in horizontal).  A
 * method is provided to paint the edge by asking the _fromNode for
 * getFromCoord(), and the _toNode for getToCoord().  A virtual
 * function provides the pen for painting.  A virtual method clones
 * pointers---this is used in TreeRing when rings are wrapped or
 * unwrapped.
 */

TreePtr::TreePtr( TreeNode * from, TreeNode * to )
            :_fromNode( from )
            ,_toNode( to )
            ,_cut( FALSE )
//------------------------------------------------
{
}

/* FIXME -- could use r to see if edge needs drawing, maybe even
 * do our own clipping
 */

void TreePtr::paint( OutputDevice *dev, TreeRect * /*r*/ )
//--------------------------------------------------------
{
    PaintInfo * pinf;   /* save the old paint info from dev */

    if( _toNode->getEnable() > TreeNode::Hidden &&
        _fromNode->getEnable() > TreeNode::Hidden ) {

        pinf = dev->getPaintInfo();
        dev->setPaintInfo( getPaintInfo() );

        TreeCoord xOff = _fromNode->getParent()->getXOff();
        TreeCoord yOff = _fromNode->getParent()->getYOff();

        _line.paint( dev, xOff, yOff );

        delete dev->getPaintInfo();
        dev->setPaintInfo( pinf );
    }
}

void TreePtr::addEdges( TreeEdgeBreaker * breaker )
//-------------------------------------------------
{
    TreeCoord x1, x2, y1, y2;

    if( _fromNode->getEnable() && _toNode->getEnable() && !_cut ) {

        _fromNode->getFromCoord( this, x1, y1 );
        _toNode->getToCoord( this, x2, y2 );

        _line.set( x1, y1, x2, y2, TreeLine::Edge );

        if( _toNode->getParent()->getSmartEdges() ) {
            breaker->addLine( &_line );
        }
    }
}

/* compare two edges for sorting purposes; comparison is done based on
 * the center point of the _toNode.
 */

static int TreePtr::comparePtrs( const TreePtr * lhP, const TreePtr * rhP )
//-------------------------------------------------------------------------
{
    return TreeNode::compareNodes( lhP->_toNode, rhP->_toNode );
}

////////////////////////////////// TreeNode ////////////////////////////

/* TreeNode is an abstract base class providing all the functionality
 * needed for graphical nodes.
 */

TreeNode::TreeNode( TreeWindow * prt )
            :_bounding()
            ,_flags( NotPlaced, Visible, 0, 0, 0 )
            ,_sibWidth( 0 )
            ,_parent( prt )
            ,_pRoot( NULL )
{
}

/* set my bounding rectangle and my sibling width.  the bounding rectangle
 * is set to be large enough to hold my name (given by the port), with
 * a buffer of NodeBuffer around the edges.  the _sibWidth is determined
 * by adding the sibling widths of all parents one level above this node,
 * dividing each width by the number of children the node has.
 */

void TreeNode::setBounding( OutputDevice *dev )
//---------------------------------------------
{
    bool sepIncluded = FALSE;

    if( !_flags.boundSet ) {
        #if DEBUG
        _nm = name();
        #endif

        _flags.boundSet = TRUE;

        int     width;
        int     height;
        char *  nodename = name();

        if( nodename != NULL ) {
            width = dev->getTextExtentX( nodename );
            height = dev->getTextExtentY( nodename );
        } else {
            width = 0;
            height = 0;
        }

        _bounding.w( width + 2 * NodeBuffer );
        _bounding.h( height + 2 * NodeBuffer );

        _sibWidth = 0;

        for( int i = getCount( ParentList ); i > 0; i -= 1 ) {
            TreeNode * node = getNode( ParentList, i - 1 );

            node->setBounding( dev );
            _sibWidth += node->getSibContrib( this, sepIncluded );
        }

        bool vert = (_parent->getDirection() == TreeVertical);
        _sibWidth = maxCoord( _sibWidth, (vert) ? _bounding.w()
                                                : _bounding.h() );
    }
}

/* get the sibling-width contribution this node has for node.  This
 * is a virtual function so that TreeRing can do the appropriate thing.
 */

TreeCoord TreeNode::getSibContrib( TreeNode * node, bool & sepInc )
//-----------------------------------------------------------------
{
    TreeCoord ret = 0;

    if( node->getLevel() != getLevel() + 1 ) return 0;

    if( _flags.enabled > Hidden ) {
        int divisor = 0;
        int lvlP1 = getLevel() + 1;

        for( int i = getCount( ChildList ); i > 0; i -= 1 ) {
            TreeNode * chNode = getNode( ChildList, i - 1 );

            if( chNode->_flags.enabled > Hidden &&
                chNode->getLevel() == lvlP1 ) {

                divisor += 1;
            }
        }

        divisor = maxInt( divisor, 1 );

        ret = _sibWidth / divisor;

        if( !sepInc ) {
            sepInc = TRUE;
        } else {
            ret += sibSep / divisor;
        }
    }

    return ret;
}

/* paint a node within its _bounding rectangle
 */

void TreeNode::paint( OutputDevice *dev, TreeRect *r )
//----------------------------------------------------
{
    /* first make sure that this node needs to be drawn:
     * it must be visible, and it must be inside the
     * invalid rectangle
     */

    if( _flags.enabled == Hidden )  return;

    if( ( r->x() + r->w() < _bounding.x() ) ||
         (r->x() > _bounding.x() + _bounding.w() ) )  return;

    if( ( r->y() + r->h() < _bounding.y() ) ||
        ( r->y() > _bounding.y() + _bounding.h() ) )  return;


    WPoint      start;
    WRect       virtBnd;
    TreeCoord   xOff = _parent->getXOff();
    TreeCoord   yOff = _parent->getYOff();
    Color       back;
    Color       fore;
    PaintInfo * pinf;
    PaintInfo * oldPinf;

    //---------- border ---------//

    virtBnd.x( (int) _bounding.x() - xOff );
    virtBnd.y( (int) _bounding.y() - yOff );
    virtBnd.w( (int) _bounding.w() );
    virtBnd.h( (int) _bounding.h() );

    pinf = getPaintInfo();
    oldPinf = dev->getPaintInfo();
    dev->setPaintInfo( pinf );

    dev->rectangle( virtBnd );

    delete pinf;
    dev->setPaintInfo( oldPinf );

    //---------- text -----------//

    if( _flags.selected ) {
        back = CUSTOM_RGB(0,0,128);
        fore = ColorWhite;
    } else {
        back = ColorLiteGray;
        fore = ColorBlack;
    }

    start.x( virtBnd.x() + NodeBuffer );
    start.y( virtBnd.y() + NodeBuffer );

    dev->drawText( start, name(), fore, back );
}

void TreeNode::addEdges( TreeEdgeBreaker * breaker )
//--------------------------------------------------
{
    if( _flags.enabled > Hidden ) {

        _lineTop.set( _bounding.left(), _bounding.top(),
                      _bounding.right() - 1, _bounding.top(),
                      TreeLine::Node );
        _lineRight.set( _bounding.right() - 1, _bounding.top(),
                        _bounding.right() - 1, _bounding.bottom() - 1,
                        TreeLine::Node );
        _lineBottom.set( _bounding.right() - 1, _bounding.bottom() - 1,
                         _bounding.left(), _bounding.bottom() - 1,
                         TreeLine::Node );
        _lineLeft.set( _bounding.left(), _bounding.bottom() - 1,
                       _bounding.left(), _bounding.top(),
                       TreeLine::Node );

        if( _parent->getSmartEdges() ) {
            breaker->addLine( &_lineTop );
            breaker->addLine( &_lineRight );
            breaker->addLine( &_lineBottom );
            breaker->addLine( &_lineLeft );
        }

        for( int i = getCount( ParentList ); i > 0; i -= 1 ) {
            getPtr( ParentList, i - 1 )->addEdges( breaker );
        }
    }
}

/* move the bounding rectangle to a given (x,y) pair.  just a little
 * cleaner than including two lines of code all over the place
 */

void TreeNode::move( TreeCoord x, TreeCoord y )
//---------------------------------------------
{
    _bounding.x( x );
    _bounding.y( y );
}

/* called when the focus comes to this node---ie. when the user clicks on
 * this node with the left or right button.  the return value was meant
 * to be in case the node should not get focus; this is currently not
 * used
 */

bool TreeNode::gettingFocus( WWindow *win )
//-----------------------------------------
{
    TreeRect tr = _bounding;

    tr.x( tr.x() - _parent->getXOff() );
    tr.y( tr.y() - _parent->getYOff() );

    _flags.selected = TRUE;
    win->invalidateRect( tr.makeWRect() );
    return TRUE;
}

/* called when a node loses focus.  the return value was meant to be
 * if the node should not lose focus, but is currently not used
 */

bool TreeNode::losingFocus( WWindow *win )
//----------------------------------------
{
    TreeRect tr = _bounding;

    tr.x( tr.x() - _parent->getXOff() );
    tr.y( tr.y() - _parent->getYOff() );

    _flags.selected = FALSE;
    win->invalidateRect( tr.makeWRect() );
    return TRUE;
}

TreeRoot * TreeNode::getRootPtr( void )
//-------------------------------------
{
    return _pRoot;
}

/*  Arrange all the trees in a list of roots of the trees.
 */

void TreeNode::arrangeAll( TreeDirection dir, TreeRootList& roots,
                           TreeRect& world, OutputDevice *dev )
//----------------------------------------------------------------
{
    TreeCoord   maxX = 0;
    TreeCoord   maxY = 0;
    TreeCoord   sibOff = sibSep;
    int         i;

    for( i = 0; i < roots.count(); i += 1 ) {
        if( roots[ i ]->enabled() ) {
            TreeCoord  sibStart = sibOff;
            TreeRect   r;
            TreeNode * node = roots[ i ]->setNode();

            roots[ i ]->setRingEnable();
            roots[ i ]->setAllBounding( dev );

            node->arrangeTree( sibOff );

            // now mop up any nodes isolated by hiding
            for( int j = node->getCount( FlatList ); j > 0; j -= 1 ) {
                TreeNode * newNode = node->getNode( FlatList, j - 1 );
                if( newNode->_flags.placed != Placed ) {
                    newNode->arrangeTree( sibOff );
                }
            }

            if( dir == TreeVertical ) {
                r.x( sibStart );
                r.y( sibSep );
            } else {

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?