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 + -
显示快捷键?