Logo Search packages:      
Sourcecode: whitedune version File versions  Download package

SceneGraphView.cpp

/*
 * SceneGraphView.cpp
 *
 * Copyright (C) 1999 Stephen F. White
 * 
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program (see the file "COPYING" for details); if 
 * not, write to the Free Software Foundation, Inc., 675 Mass Ave, 
 * Cambridge, MA 02139, USA.
 */

#include "stdafx.h"

#include "SceneGraphView.h"
#include "Scene.h"
#include "Node.h"
#include "Proto.h"
#include "Path.h"
#include "FieldValue.h"
#include "Field.h"
#include "EventIn.h"
#include "EventOut.h"
#include "SFNode.h"
#include "MFNode.h"
#include "MoveCommand.h"
#include "RouteCommand.h"
#include "UnRouteCommand.h"
#include "CommandList.h"
#include "resource.h"
#include "Util.h"

#define SOCKET_WIDTH 6
#define SOCKET_HEIGHT 6
#define SOCKET_SPACING 2

#define BORDER_WIDTH    2 
#define ICON_SIZE 16
#define NODE_WIDTH      190

#define ADD_WIDTH       8
#define ADD_HEIGHT      4

#ifdef WIN32
// near windows canvas limit 
# define MAX_Y           8000
#else
// near motif canvas limit
# define MAX_Y           32000
#endif

#define MINIMAL_SIZE    (BORDER_WIDTH + 1 + ICON_SIZE)   

// position from left of node to icon
#define ICON_OFFSET     (BORDER_WIDTH + SOCKET_WIDTH + ICON_SIZE)   

// position from left of node to text
#define TEXT_OFFSET     (ICON_OFFSET + ICON_SIZE + 4)   

#define LINE_STUB (SOCKET_WIDTH + BORDER_WIDTH + 2)

#define SHADOW_OFFSET   1

#define AUTOSCROLL_MARGIN   10
#define AUTOSCROLL_AMOUNT   20

static int  currentX, currentY;

// maximum size for drawing to bitmap
#define MAX_BACK_WIDTH 500
#define MAX_BACK_HEIGHT 500

#define MoveTo(dc, x, y)      { currentX = x; currentY = y; }
#define LineTo(dc, x, y)      { swDrawLine(dc, currentX, currentY, x, y); \
                          currentX = x; currentY = y; }
#define InvalidateTo(wnd, x, y)     { int minX = MIN(currentX, x); \
                            int minY = MIN(currentY, y); \
                          int maxX = MAX(currentX, x); \
                          int maxY = MAX(currentY, y); \
swInvalidateRect(wnd, minX, minY, maxX - minX + 2, maxY - minY + 2); \
                   currentX = x; currentY = y; }

static void
expose(void *data, int x, int y, int width, int height)
{
    ((SceneGraphView *) data)->OnDraw(x, y, width, height);
}

static void
keyCB(void *data, int key, int value, int x, int y, int modifiers)
{
    if (key == SW_MOUSE1) {
        if (value) {
            ((SceneView *) data)->OnLButtonDown(x, y, modifiers);
        } else {
            ((SceneView *) data)->OnLButtonUp(x, y, modifiers);
        }
    } else if (value) {
        ((SceneView *) data)->OnKeyDown(key, x, y, modifiers);
    } else {
        ((SceneView *) data)->OnKeyUp(key, x, y, modifiers);
    }
}

static void
mouseCB(void *data, int x, int y, int modifiers)
{
    ((SceneView *) data)->OnMouseMove(x, y, modifiers);
}

static void
mouseEnterCB(void *data, int value)
{
    if (value) {
      ((SceneView *) data)->OnMouseEnter();
    } else {
      ((SceneView *) data)->OnMouseLeave();
    }
}

SceneGraphView::SceneGraphView(Scene *scene, SWND parent)
  : SceneView(scene, parent)
{
    int           width, height;
    swGetSize(parent, &width, &height);

    _lastXPosition = 0;
    _lastYPosition = 0;
    _maxYPosition = 0;
    _mode = NONE;
    _dstNode = NULL;
    _dstSocket = -1;
    _dstSide = 0;
    _srcNode = NULL;
    _srcSocket = -1;
    _srcSide = 0;
    _scroller = swCreateScrolledWindow(0, 0, width, height, parent);
    _window = swCreateCanvas("", 0, 0, width, height, _scroller);
    swScrolledWindowSetChild(_scroller, _window);
    swSetExposeCallback(_window, expose);
    swSetKeyCallback(_window, keyCB);
    swSetMouseCallback(_window, mouseCB);
    swSetEnterCallback(_window, mouseEnterCB);
    swSetClientData(_window, this);
    _face = swGetWindowColor(_window, SW_COLOR_FACE);
    _highlight = swGetWindowColor(_window, SW_COLOR_TSHADOW);
    _shadow = swGetWindowColor(_window, SW_COLOR_BSHADOW);
    int mapFrom[4] = { 0x808000, 0x000000, 0xC0C0C0, 0x808080 };
    int mapTo[4] = { _face, _shadow, _highlight, _face };
    _nodeBitmap = swLoadMappedBitmap(_window, IDB_NODE_ICONS, mapFrom, mapTo, 1);
    _socketBitmap = swLoadMappedBitmap(_window, IDB_EMPTY_SOCKET, mapFrom, mapTo, 4); 
    _socketBitmapRecommended = swLoadMappedBitmap(_window, IDB_RECOMMENDED_SOCKET, mapFrom, mapTo, 4); 
    BuildSocketBitmaps();
    _autoScrolling = false;
    _zoom = 1.0;
}

SceneGraphView::~SceneGraphView()
{
    for (int i = 0; i < 20; i++) {
      swDestroyBitmap(_socketBitmaps[i]);
    }
    swDestroyBitmap(_nodeBitmap);
    swDestroyBitmap(_socketBitmap);
    swDestroyWindow(_window);
    swDestroyWindow(_scroller);
}

void SceneGraphView::Initialize()
{
    const NodeList     *nodes = _scene->getNodes();

    _lastXPosition = _lastYPosition = 0;

    int i;
    for (i = 0; i < nodes->size(); i++) {
      Node  *node = nodes->get(i);

      if (node->isInScene(_scene) && node != _scene->getRoot()) {
            setZoomGraphPosition(node, 0, 0);
      }
    }
    for (i = 0; i < nodes->size(); i++) {
      Node  *node = nodes->get(i);

      if (node->isInScene(_scene) && node != _scene->getRoot()) {
          Position(node);
      }
    }
    swInvalidateWindow(_window);
    swSetScrollSizes(_scroller, _lastXPosition, _maxYPosition);
}

void SceneGraphView::OnDraw(int x, int y, int width, int height)
{
    SDC           dc, frontDC;

    const Path *sel = _scene->getSelection();
    Node *current = sel ? sel->getNode() : NULL;

    if (width == 0 || height == 0) {
      swGetSize(_window, &width, &height);
    }

    frontDC = swCreateDC(_window);
    dc = swCreateBitmapDC(frontDC, x + width, y + height);

    if (dc == NULL) {
      swDestroyDC(frontDC);
        return;
    }

    swSetFGColor(dc, 0x000000);
    swFillRect(dc, x, y, width, height);

    int           i;

    const NodeList    *nodes = _scene->getNodes();

    for (i = 0; i < nodes->size(); i++) {
      Node  *node = nodes->get(i);
      int         nx, ny, nw, nh;
      getZoomGraphPosition(nx, ny, node);
      getZoomGraphSize(nw, nh, node);
      if (node->isInScene(_scene)
          && node != current
          && node != _scene->getRoot()
          && nx + nw >= x && nx <= x + width
          && ny + nh >= y && ny <= y + height) {
          DrawNode(dc, node, nx, ny);
      }
    }

    if (current) {
      int         nx, ny, nw, nh;
      getZoomGraphPosition(nx, ny, current);
      getZoomGraphSize(nw, nh, current);
      if (current->isInScene(_scene)
          && current != _scene->getRoot()
          && nx + nw >= x && nx <= x + width
          && ny + nh >= y && ny <= y + height) {
          DrawNode(dc, current, nx, ny);
      }
    }

    for (i = 0; i < nodes->size(); i++) {
      Node  *node = nodes->get(i);

      if (node->isInScene(_scene)) {
          DrawRoutes(dc, node);
      }
    }
    
    int           cindex;

    if (_mode == ROUTING) {
        Proto *proto = _srcNode->getProto();
      if (_srcSide == 1) {
            if ((_srcNode->getType() == NODE_SCRIPT) &&
                (proto->getNumEventOuts() == _srcSocket)) {
                cindex = LAST_TYPE + 1;
                if ((_dstNode != NULL) && (_srcNode != _dstNode)) {
                    Proto *dstProto = _dstNode->getProto();
                    if ((_dstSocket > 0) 
                        && (_dstSocket < dstProto->getNumEventIns()))
                        cindex = dstProto->getEventIn(_dstSocket)->getType();
                }
            } else
              cindex = proto->getEventOut(_srcSocket)->getType();
      } else {
            if ((_srcNode->getType() == NODE_SCRIPT) &&
                (proto->getNumEventIns() == _srcSocket)) {
                cindex = LAST_TYPE + 1;
                if ((_dstNode != NULL) && (_srcNode != _dstNode)) {
                    Proto *dstProto = _dstNode->getProto();
                    if ((_dstSocket > 0) 
                        && (_dstSocket < dstProto->getNumEventOuts()))
                        cindex = dstProto->getEventOut(_dstSocket)->getType();
                }
            } else
              cindex = proto->getEventIn(_srcSocket)->getType();
      }

      DrawRoute(dc, 
          GetSocketPosition(_srcNode, _srcSocket, _srcSide),
           _point1, _typeColors[cindex] );
    } else if (_mode == CUTTING) {
      swSetFGColor(dc, 0x0000ff);
      swDrawLine(dc, _point1.x, _point1.y, _point2.x, _point2.y);
    }

    swCopyRect(dc, frontDC, x, y, x, y, width, height);
    swDestroyDC(frontDC);
    swDestroyDC(dc);
}

void SceneGraphView::OnSize(int width, int height)
{
    swSetSize(_scroller, width, height);
    swSetScrollSizes(_scroller, _lastXPosition, _maxYPosition);
}

void SceneGraphView::OnMouseLeave()
{
#ifndef HAVE_BUG_IN_LESSTIF
//
// don't ask me, why some versions of lesstif/openmotif see
// highlighting of a node socket in the route view as a leaving of window...
//
    if (_dstNode)
    {
      InvalidateNode(_dstNode);
      _dstNode = NULL;
      _dstSocket = -1;
    }
#endif
}

void SceneGraphView::YPosition(int width, int height)
{
    if ((_lastYPosition + height + ADD_HEIGHT) < MAX_Y) {
        _lastYPosition += height + ADD_HEIGHT;
        if (_maxYPosition < MAX_Y)
           _maxYPosition = _lastYPosition;
    } else {
        _lastYPosition =  height + ADD_HEIGHT;
        _lastXPosition += width + ADD_WIDTH ; 
        _maxYPosition = MAX_Y;
    }
}

void SceneGraphView::accountGraphSize(Node *node)
{
    int           height = 0;
    int           eventIns = node->getProto()->getNumEventIns();
    int           eventOuts = node->getProto()->getNumEventOuts();
    int           sockets = MAX(eventIns, eventOuts);
    if (node->getType() == NODE_SCRIPT)
         sockets++;
    height = sockets * SOCKET_HEIGHT + 
             (sockets + 1) * SOCKET_SPACING + BORDER_WIDTH * 2;
    height = MAX(height, ICON_SIZE + BORDER_WIDTH * 2);

    setGraphSize(node, NODE_WIDTH, height);
}

void SceneGraphView::accountGraphPosition(Node *node)
{
    int     width, height;
    getZoomGraphSize(width, height, node);
    width = NODE_WIDTH + LINE_STUB;
    _lastXPosition = MAX(_lastXPosition, ADD_WIDTH + width);
    YPosition(width, height);
    setZoomGraphPosition(node, _lastXPosition - width , _lastYPosition - height);
}

void SceneGraphView::Position(Node *node)
{
    int width, height;
    getZoomGraphPosition(width, height, node);
    if (height == 0) {
        accountGraphSize(node);
        accountGraphPosition(node);
    }
}

void SceneGraphView::DrawNode(SDC dc, Node *node, int xPos, int yPos)
{
    int           eventIns = node->getProto()->getNumEventIns();
    int           eventOuts = node->getProto()->getNumEventOuts();
    int           width, height;

    getZoomGraphSize(width, height, node);

    int           i;
    int           y;

    SBITMAP sbitmap;

    for (i = 0; i < BORDER_WIDTH; i++) {
      swDraw3DRect(dc, _window, xPos + i, yPos + i,
                     width - i * 2, height - i * 2);
    }

    const Path *sel = _scene->getSelection();
    Node *current = sel ? sel->getNode() : NULL;
    if (current == node)
        swSetFGColor(dc, 0xFF0000);
    else
        swSetFGColor(dc, _face);
    int rectY = yPos + BORDER_WIDTH; 
    int rectHeight = height - BORDER_WIDTH * 2;
    swFillRect(dc, xPos + BORDER_WIDTH, rectY,
               width - BORDER_WIDTH * 2, rectHeight);

    if (height > ICON_SIZE)
        swDrawBitmap(dc, _nodeBitmap, node->getType() * ICON_SIZE, 0,
                     xPos + ICON_OFFSET, yPos + height / 2 - 8, 
                     ICON_SIZE, ICON_SIZE);

    if (_zoom != 1.0)
        return;

    if (current == node) {
        swSetFGColor(dc, _face);
        int rectWidth = SOCKET_WIDTH + 2 * SOCKET_SPACING;
        swFillRect(dc, xPos + BORDER_WIDTH, rectY, rectWidth, rectHeight);
        swFillRect(dc, xPos + width - rectWidth - BORDER_WIDTH, rectY,
                   rectWidth, rectHeight);
    }

    MyString name;
    name=node->getName();
    if (name[0]==0)
       name=node->getProto()->getName();
    swSetFGColor(dc, 0x000000);
    swDrawText(dc, xPos + TEXT_OFFSET, yPos + height / 2 + 6, name);

    y = yPos + BORDER_WIDTH + SOCKET_SPACING;
    for (i = 0; i < eventIns; i++) {
      EventIn            *eventIn = node->getProto()->getEventIn(i);
      SBITMAP selectedSocketBitmap = _socketBitmaps[eventIn->getType()];
      const char     *name = eventIn->getName();
        bool drawName = false;
      if (node == _dstNode && _dstSide == 0 && _dstSocket == i && 
            (_mode != ROUTING || _srcSide == 1 && 
             Scene::validRoute(_srcNode, _srcSocket, _dstNode, _dstSocket))) {
          sbitmap = selectedSocketBitmap;
            drawName = true;
      } else if (_mode == ROUTING && node == _srcNode && _srcSide == 0 
                   && _srcSocket == i) {
          sbitmap = selectedSocketBitmap;
            drawName = true;
      } else if (node->getInput(i).size() > 0) {
          sbitmap = selectedSocketBitmap;
      } else if (eventIn->getFlags() & EIF_RECOMMENDED) {
            sbitmap = _socketBitmapRecommended;
      } else {
          sbitmap = _socketBitmap;
      }
        if (drawName)
          DrawSocketName(dc, xPos + BORDER_WIDTH + SOCKET_WIDTH 
                               + SOCKET_SPACING * 2, y + SOCKET_HEIGHT / 2, 
                           name, false);
      swDrawBitmap(dc, sbitmap, 0, 0, 
                xPos + BORDER_WIDTH + SOCKET_SPACING, y,
            SOCKET_WIDTH, SOCKET_HEIGHT);
      y += SOCKET_HEIGHT + SOCKET_SPACING;
    }
    if (node->getType() == NODE_SCRIPT) {
      sbitmap = _socketBitmap;
        bool drawName = false;
        if (_mode == ROUTING && node == _srcNode && _srcSide == 0 
            && _srcSocket == i) {
            if (_dstSocket >= 0) {
                Proto *proto = _dstNode->getProto();
                if (_dstSocket < proto->getNumEventOuts()) {
                    int type = proto->getEventOut(_dstSocket)->getType();
                    sbitmap = _socketBitmaps[type];
                }
            }
            drawName = true;
      } else if (node == _dstNode && _dstSide == 0 && _dstSocket == i && 
             (_mode != ROUTING || _srcSide == 1 && 
             Scene::validRoute(_srcNode, _srcSocket, _dstNode, _dstSocket))) {
            drawName = true; 
            if ((_mode == ROUTING) && (_srcSocket >= 0)) {
                Proto *proto = _srcNode->getProto();
                if (_srcSocket < proto->getNumEventOuts()) {
                    int type = proto->getEventOut(_srcSocket)->getType();
                    sbitmap = _socketBitmaps[type];
                }
            }
        }
        if (drawName)
          DrawSocketName(dc, xPos + BORDER_WIDTH + SOCKET_WIDTH 
                               + SOCKET_SPACING * 2, y + SOCKET_HEIGHT / 2, 
                           "(connect anything)", false);
        swDrawBitmap(dc, sbitmap, 0, 0,
                       xPos + BORDER_WIDTH + SOCKET_SPACING, y,
                     SOCKET_WIDTH, SOCKET_HEIGHT);
    }
    y = yPos + BORDER_WIDTH + SOCKET_SPACING;
    for (i = 0; i < eventOuts; i++) {
      EventOut       *eventOut = node->getProto()->getEventOut(i);
      SBITMAP selectedSocketBitmap = _socketBitmaps[eventOut->getType()];
      const char     *name = eventOut->getName();
        bool drawName = false;
      if (node == _dstNode && _dstSide == 1 && _dstSocket == i && 
            (_mode != ROUTING || _srcSide == 0 && 
             Scene::validRoute(_dstNode, _dstSocket, _srcNode, _srcSocket))) {
          sbitmap = selectedSocketBitmap;
            drawName = true;
      } else if (_mode == ROUTING && node == _srcNode && _srcSide == 1 && 
                   _srcSocket == i) {
          sbitmap = selectedSocketBitmap;
            drawName = true;
      } else if (node->getOutput(i).size() > 0)  { 
          sbitmap = selectedSocketBitmap;
      } else if (eventOut->getFlags() & EOF_RECOMMENDED) {
            sbitmap = _socketBitmapRecommended;
      } else {
          sbitmap = _socketBitmap;
      }
        if (drawName)
          DrawSocketName(dc, xPos + width - BORDER_WIDTH - SOCKET_SPACING*2 
                               - SOCKET_WIDTH, y + SOCKET_HEIGHT / 2, 
                           name, true);
      swDrawBitmap(dc, sbitmap, 0, 0,
            xPos + width - BORDER_WIDTH - SOCKET_SPACING - SOCKET_WIDTH, y,
            SOCKET_WIDTH, SOCKET_HEIGHT);
      y += SOCKET_HEIGHT + SOCKET_SPACING;
    }
    if (node->getType() == NODE_SCRIPT) {
      sbitmap = _socketBitmap;
        bool drawName = false;
        if (_mode == ROUTING && node == _srcNode && _srcSide == 1 && 
            _srcSocket == i) {
            if (_dstSocket >= 0) {
                Proto *proto = _dstNode->getProto();
                if (_dstSocket < proto->getNumEventIns()) {
                    int type = proto->getEventIn(_dstSocket)->getType();
                    sbitmap = _socketBitmaps[type];
                }
            }
            drawName = true;
      } else if (node == _dstNode && _dstSide == 1 && _dstSocket == i
                 && (_mode != ROUTING || _srcSide == 0)) {
            drawName = true; 
            if ((_mode == ROUTING) && (_srcSocket >= 0)) {
                Proto *proto = _srcNode->getProto();
                if (_srcSocket < proto->getNumEventIns()) {
                    int type = proto->getEventIn(_srcSocket)->getType();
                    sbitmap = _socketBitmaps[type];
                }
            }
        }    
        if (drawName)
          DrawSocketName(dc, 
                xPos + width - BORDER_WIDTH - SOCKET_SPACING*2 - SOCKET_WIDTH,
                y + SOCKET_HEIGHT / 2, "(connect anything)", true);
      swDrawBitmap(dc, sbitmap, 0, 0, 
                xPos + width - BORDER_WIDTH - SOCKET_SPACING - SOCKET_WIDTH, y,
                SOCKET_WIDTH, SOCKET_HEIGHT);
    }
}

void SceneGraphView::DrawRoute(SDC dc, Point start, Point end, int color)
{
    int           midx = (start.x + end.x) / 2;
    int           midy = (start.y + end.y) / 2;

    if (end.x - start.x < LINE_STUB * 2) {
      swSetFGColor(dc, 0x000000);
      MoveTo(dc, start.x + SHADOW_OFFSET, start.y + SHADOW_OFFSET);
      LineTo(dc, start.x + LINE_STUB + SHADOW_OFFSET, start.y + SHADOW_OFFSET);
      LineTo(dc, start.x + LINE_STUB + SHADOW_OFFSET, midy + SHADOW_OFFSET);
      LineTo(dc, end.x - LINE_STUB + SHADOW_OFFSET, midy + SHADOW_OFFSET);
      LineTo(dc, end.x - LINE_STUB + SHADOW_OFFSET, end.y + SHADOW_OFFSET);
      LineTo(dc, end.x + SHADOW_OFFSET, end.y + SHADOW_OFFSET);
      swSetFGColor(dc, color);
      MoveTo(dc, start.x, start.y);
      LineTo(dc, start.x + LINE_STUB, start.y);
      LineTo(dc, start.x + LINE_STUB, midy);
      LineTo(dc, end.x - LINE_STUB, midy);
      LineTo(dc, end.x - LINE_STUB, end.y);
      LineTo(dc, end.x, end.y);
    } else {
      swSetFGColor(dc, 0x000000);
      MoveTo(dc, start.x + SHADOW_OFFSET, start.y + SHADOW_OFFSET);
      LineTo(dc, midx + SHADOW_OFFSET, start.y + SHADOW_OFFSET);
      LineTo(dc, midx + SHADOW_OFFSET, end.y + SHADOW_OFFSET);
      LineTo(dc, end.x + SHADOW_OFFSET, end.y + SHADOW_OFFSET);
      swSetFGColor(dc, color);
      MoveTo(dc, start.x, start.y);
      LineTo(dc, midx, start.y);
      LineTo(dc, midx, end.y);
      LineTo(dc, end.x, end.y);
    }
}

bool SceneGraphView::IntersectRoute(Point start, Point end, 
                            Point rStart, Point rEnd)
{
    int           midx = (rStart.x + rEnd.x) / 2;
    int           midy = (rStart.y + rEnd.y) / 2;
    bool    rc;

    if (rEnd.x - rStart.x < LINE_STUB * 2) {
      rc = Util::IntersectLines(start.x, start.y, end.x, end.y,
                          rStart.x, rStart.y,
                          rStart.x + LINE_STUB, rStart.y)
        || Util::IntersectLines(start.x, start.y, end.x, end.y,
                          rStart.x + LINE_STUB, rStart.y,
                          rStart.x + LINE_STUB, midy)
        || Util::IntersectLines(start.x, start.y, end.x, end.y,
                          rStart.x + LINE_STUB, midy,
                          rEnd.x - LINE_STUB, midy)
        || Util::IntersectLines(start.x, start.y, end.x, end.y,
                          rEnd.x - LINE_STUB, midy,
                          rEnd.x - LINE_STUB, rEnd.y)
        || Util::IntersectLines(start.x, start.y, end.x, end.y,
                          rEnd.x - LINE_STUB, rEnd.y,
                          rEnd.x, rEnd.y);
    } else {
      rc = Util::IntersectLines(start.x, start.y, end.x, end.y,
                          rStart.x, rStart.y,
                          midx, rStart.y)
        || Util::IntersectLines(start.x, start.y, end.x, end.y,
                          midx, rStart.y,
                          midx, rEnd.y)
        || Util::IntersectLines(start.x, start.y, end.x, end.y,
                          midx, rEnd.y,
                          rEnd.x, rEnd.y);
    }
    return rc;
}

void SceneGraphView::InvalidateRoute(Point start, Point end)
{
    int           midx = (start.x + end.x) / 2;
    int           midy = (start.y + end.y) / 2;

    swInvalidateRect(_window, start.x - 3, start.y - 2, 6, 6);
    swInvalidateRect(_window, end.x, end.y - 2, 6, 6);
    if (end.x - start.x < LINE_STUB * 2) {
      MoveTo(_window, start.x, start.y);
      InvalidateTo(_window, start.x + LINE_STUB, start.y);
      InvalidateTo(_window, start.x + LINE_STUB, midy);
      InvalidateTo(_window, end.x - LINE_STUB, midy);
      InvalidateTo(_window, end.x - LINE_STUB, end.y);
      InvalidateTo(_window, end.x, end.y);
    } else {
      MoveTo(_window, start.x, start.y);
      InvalidateTo(_window, midx, start.y);
      InvalidateTo(_window, midx, end.y);
      InvalidateTo(_window, end.x, end.y);
    }
}

void SceneGraphView::DrawRoutes(SDC dc, Node *node)
{
    int           eventOuts = node->getProto()->getNumEventOuts();

    for (int i = 0; i < eventOuts; i++) {
      for (SocketList::Iterator *j = node->getOutput(i).first(); j != NULL;
           j = j->next()) {
          Socket  s = j->item();
          int c = _typeColors[node->getProto()->getEventOut(i)->getType()];
          Point   dest = GetSocketPosition(s._node, s._index, 0);
          DrawRoute(dc, GetSocketPosition(node, i, 1), 
                    Point(dest.x - SOCKET_WIDTH / 2, dest.y), c);
      }
    }

}

void SceneGraphView::DrawSocketName(SDC dc, int x, int y, const char *name,
                            bool rightAlign)
{
    const int     margin = 3;
    int           width = swGetStringWidth(swGetDefaultFont(), name) + margin * 2;
    int           descent = swGetFontDescent(swGetDefaultFont());
    int           ascent = swGetFontAscent(swGetDefaultFont());
    int           height = ascent + descent + margin * 2;
    if (rightAlign) x -= width;
    y -= height / 2;

    swSetFGColor(dc, _face);
    swFillRect(dc, x, y, width, height);
    swDraw3DRect(dc, _window, x, y, width, height);
    swSetFGColor(dc, 0x000000);
    swDrawText(dc, x + margin, y + ascent + margin, name);
}

void SceneGraphView::InvalidateNode(Node *node)
{
    int           i;

    if (!node) return;

    int           eventIns = node->getProto()->getNumEventIns();
    int           eventOuts = node->getProto()->getNumEventOuts();
    int           x, y, width, height;

    getZoomGraphPosition(x, y, node);
    getZoomGraphSize(width, height, node);
    swInvalidateRect(_window, x, y, width + 1, height + 1);
    for (i = 0; i < eventOuts; i++) {
      for (SocketList::Iterator *j = node->getOutput(i).first(); j != NULL;
           j = j->next()) {
          Socket  s = j->item();
          InvalidateRoute(GetSocketPosition(node, i, 1), 
                    GetSocketPosition(s._node, s._index, 0) - Point(SOCKET_WIDTH / 2, 0));
      }
    }
    for (i = 0; i < eventIns; i++) {
      for (SocketList::Iterator *j = node->getInput(i).first(); j != NULL;
           j = j->next()) {
          Socket  s = j->item();
          InvalidateRoute(GetSocketPosition(s._node, s._index, 1),
                      GetSocketPosition(node, i, 0) - Point(SOCKET_WIDTH / 2, 0));
      }
    }
}

void SceneGraphView::InvalidateNodeRec(Node *node)
{
    Position(node);
    InvalidateNode(node);
    for (int i = 0; i < node->getProto()->getNumFields(); i++) {
        if (node->getField(i) != NULL) {
          if (node->getField(i)->getType() == SFNODE) {
              Node    *child = ((SFNode *) node->getField(i))->getValue();
              if (child != NULL) InvalidateNodeRec(child);
          } else if (node->getField(i)->getType() == MFNODE) {
              NodeList *value = ((MFNode *) node->getField(i))->getValues();
              for (int j = 0; j < value->size(); j++) {
                InvalidateNodeRec(value->get(j));
              }
          }
        }
    }
}

Node *SceneGraphView::HitTest(int x, int y) const
{
    const NodeList    *nodes = _scene->getNodes();

    for (int i = 0; i < nodes->size(); i++) {
      Node  *node = nodes->get(i);
      int   nx, ny, width, height;
      getZoomGraphPosition(nx, ny, node);
      getZoomGraphSize(width, height, node);
      if (x >= nx && y >= ny && x < nx + width && y < ny + height)
          return node;
    }
    return NULL;
}

int SceneGraphView::SocketHitTest(int x, int y, Node *node, int *side) const
{
    int           nx, ny, width, height;

    if (_zoom != 1.0)
        return -1;
    getZoomGraphPosition(nx, ny, node);
    getZoomGraphSize(width, height, node);
    int     px = x - nx;
    int     py = y - ny;
    int     sock = (py - BORDER_WIDTH - SOCKET_SPACING) 
               / (SOCKET_HEIGHT + SOCKET_SPACING);
    int socketsIn = node->getProto()->getNumEventIns();
    int socketsOut = node->getProto()->getNumEventOuts();
    if (node->getType() == NODE_SCRIPT) {
        socketsIn++;
        socketsOut++;
    }
    if (px >= BORDER_WIDTH + SOCKET_SPACING
      && px < BORDER_WIDTH + SOCKET_SPACING + SOCKET_WIDTH 
      && sock < socketsIn) {
      *side = 0;  // left side, inputs
      return sock;
    } else if (px >= width - BORDER_WIDTH - SOCKET_WIDTH - SOCKET_SPACING
             && px < width - BORDER_WIDTH - SOCKET_SPACING
             && sock < socketsOut) {
      *side = 1;  // right side, outputs
      return sock;
    } else {
      return -1;
    }
}

void SceneGraphView::OnLButtonDown(int x, int y, int modifiers) 
{
    Node       *node = HitTest(x, y);
    const Path *sel = _scene->getSelection();
    Node       *current = sel ? sel->getNode() : NULL;

    swSetFocus(_wnd);
    if (node) {
      if (current != node) {
          _scene->setSelection(node);
          _scene->UpdateViews(this, UPDATE_SELECTION);
      }
      if (_dstSocket != -1) {
          _mode = ROUTING;
          _srcNode = node;
          _srcSocket = _dstSocket;
          _srcSide = _dstSide;
          _point1 = _point2 = Point(x, y);
      } else {
          _mode = TRACKING;
          _dstNode = node;
          int           nx, ny;
          getZoomGraphPosition(nx, ny, node);
          _point2 = Point(x - nx, y - ny);
      }
    } else {
      _mode = CUTTING;
      _point1 = _point2 = Point(x, y);
    }
    swSetCapture(_window);
}

void SceneGraphView::OnLButtonUp(int x, int y, int modifiers) 
{
    swReleaseCapture(_window);
    if (_autoScrolling) {
      swKillTimer(_timer);
      _autoScrolling = false;
    }
    if (_mode == TRACKING) {
      _dstNode = NULL;
    } else if (_mode == ROUTING) {
      if (_dstNode != NULL && _dstSocket != -1 && _dstSide != _srcSide) {
          // got a route, try to assign it
          Node    *src, *dst;
          int            srcSocket, dstSocket;

          if (_srcSide == 0) {
            // routing backwards
            src = _dstNode;
            dst = _srcNode;
            srcSocket = _dstSocket;
            dstSocket = _srcSocket;
          } else {
            src = _srcNode;
            dst = _dstNode;
            srcSocket = _srcSocket;
            dstSocket = _dstSocket;
          }
          if (Scene::validRoute(src, srcSocket, dst, dstSocket)) {
            _scene->execute(
                new RouteCommand(src, srcSocket, dst, dstSocket));
          }   
      }
      InvalidateRoute(GetSocketPosition(_srcNode, _srcSocket, _srcSide),
                  _point1);
      InvalidateNode(_srcNode);
      InvalidateNode(_dstNode);
    } else if (_mode == CUTTING) {
      CutRoutes(_point1, _point2);
      int top = MIN(_point1.y, _point2.y);
      int bottom = MAX(_point1.y, _point2.y);
      int left = MIN(_point1.x, _point2.x);
      int right = MAX(_point1.x, _point2.x);
      swInvalidateRect(_window, left, top, right - left + 1, bottom - top + 1);
    }
    _mode = NONE;
}

void SceneGraphView::CutRoutes(const Point &start, const Point &end)
{
    CommandList       *list = NULL;
    const NodeList    *nodes = _scene->getNodes();

    for (int i = 0; i < nodes->size(); i++) {
      Node  *node = nodes->get(i);

      if (node->isInScene(_scene)) {
          int           eventOuts = node->getProto()->getNumEventOuts();

          for (int j = 0; j < eventOuts; j++) {
            for (SocketList::Iterator *k = node->getOutput(j).first(); k != NULL;
                 k = k->next()) {
                Socket  s = k->item();
                if (IntersectRoute(start, end, GetSocketPosition(node, j, 1), 
                  GetSocketPosition(s._node, s._index, 0) - Point(SOCKET_WIDTH / 2, 0))) {
                  if (!list) list = new CommandList();
                  list->append(new UnRouteCommand(node, j, s._node, s._index));
                }
            }
          }
      }
    }
    if (list) _scene->execute(list);
}

void SceneGraphView::OnMouseMove(int x, int y, int modifiers) 
{
    if (_mode != NONE) {
      CheckAutoScroll(x, y);
      _lastXPosition = MAX(_lastXPosition, x);
      _lastYPosition = MAX(_lastYPosition, y);
      _maxYPosition = MAX(_maxYPosition, _lastYPosition);
      swSetScrollSizes(_scroller, _lastXPosition, _maxYPosition);
    }
    DoMouseMove(x, y, modifiers);
}

void SceneGraphView::DoMouseMove(int px, int py, int modifiers)
{
    if ((_mode == TRACKING) && (_dstNode!=NULL)) {
      int   oldX, oldY, width, height;
      getZoomGraphPosition(oldX, oldY, _dstNode);
      getZoomGraphSize(width, height, _dstNode);
      InvalidateNode(_dstNode);
      int newX = MAX(px - _point2.x, 0);
      int newY = MAX(py - _point2.y, 0);
      if (newX != oldX || newY != oldY) {
          InvalidateNode(_dstNode);
          setZoomGraphPosition(_dstNode, newX, newY);
          InvalidateNode(_dstNode);
          _lastXPosition = MAX(_lastXPosition, newX + width + LINE_STUB);
            _lastYPosition = MAX(_lastYPosition, newY + height);
            _maxYPosition = MAX(_maxYPosition, _lastYPosition);
            int sx, sy;
            swGetScrollPosition(_scroller, &sx, &sy);
          swSetScrollSizes(_scroller, _lastXPosition, _maxYPosition);
            swSetScrollPosition(_scroller, sx, sy);
      }
    } else if (_mode == ROUTING) {
      InvalidateRoute(GetSocketPosition(_srcNode, _srcSocket, _srcSide),
                  _point1);
      _point1 = Point(px, py);
      InvalidateRoute(GetSocketPosition(_srcNode, _srcSocket, _srcSide),
                  _point1);

      HighlightSocket(_point1);
    } else if (_mode == CUTTING) {
      int       top, left, right, bottom;
      top = MIN(_point1.y, _point2.y);
      bottom = MAX(_point1.y, _point2.y);
      left = MIN(_point1.x, _point2.x);
      right = MAX(_point1.x, _point2.x);
      swInvalidateRect(_window, left, top, right - left + 1, bottom - top + 1);
      _point2 = Point(px, py);
      top = MIN(_point1.y, _point2.y);
      bottom = MAX(_point1.y, _point2.y);
      left = MIN(_point1.x, _point2.x);
      right = MAX(_point1.x, _point2.x);
      swInvalidateRect(_window, left, top, right - left + 1, bottom - top + 1);
    } else {
      HighlightSocket(Point(px, py));
    }
}

static int
timerCB(void *data)
{
    return ((SceneGraphView *) data)->OnTimer();
}

void SceneGraphView::CheckAutoScroll(int px, int py)
{
    bool    autoScroll = true;
    int           x, y, width, height, sx, sy;
    int           dx = 0, dy = 0;

    swGetPosition(_scroller, &x, &y);
    swGetScrollViewportSize(_scroller, &width, &height);
    swGetScrollPosition(_scroller, &sx, &sy);
    px -= sx;
    py -= sy;
    _autoScrollPX = px;
    _autoScrollPY = py;

    if (px < AUTOSCROLL_MARGIN) {
      dx = -AUTOSCROLL_AMOUNT;
    } else if (px > x + width - AUTOSCROLL_MARGIN) {
      dx = AUTOSCROLL_AMOUNT;
    } else if (py < AUTOSCROLL_MARGIN) {
      dy = -AUTOSCROLL_AMOUNT;
    } else if (py > y + height - AUTOSCROLL_MARGIN) {
      dy = AUTOSCROLL_AMOUNT;
    } else {
      autoScroll = false;
    }

    if (autoScroll && !_autoScrolling) {   // start scrolling
      _timer = swSetTimer(_window, 70, timerCB, this);
      _autoScrollDX = dx;
      _autoScrollDY = dy;
      _autoScrolling = true;
    }
    if (!autoScroll && _autoScrolling) {   // stop scrolling
      swKillTimer(_timer);
      _autoScrolling = false;
    }
}

void SceneGraphView::HighlightSocket(Point point)
{
    // check if we're over a socket
    Node *node = HitTest(point.x, point.y);
    int     socket = -1;
    int side = -1;

    if (node) {
      socket = SocketHitTest(point.x, point.y, node, &side);
    }

    if (_dstNode && node != _dstNode)
    {
      InvalidateNode(_dstNode);
    } else if (node && (socket != _dstSocket || side != _dstSide)) {
      InvalidateNode(node);
    }
    _dstNode = node;
    _dstSocket = socket;
    _dstSide = side;
}

void SceneGraphView::OnUpdate(SceneView *sender, int type, Hint *hint) 
{
    NodeUpdate       *nodeUpdate;
    RouteUpdate      *routeUpdate;

    switch (type) {
      case UPDATE_ALL:
      Initialize();
      break;
      case UPDATE_SELECTION:
      case UPDATE_SELECTION_NAME:
      InvalidateNode(_scene->getSelection()->getNode());
        swInvalidateWindow(_window);
      break;
      case UPDATE_FIELD:
      // ignore field updates for now
      break;
      case UPDATE_CHANGE_INTERFACE_NODE:
      nodeUpdate = (NodeUpdate *) hint;
        // when the number of events change, size can change
        accountGraphSize(nodeUpdate->node);
      case UPDATE_ADD_NODE:
      case UPDATE_REMOVE_NODE:
      nodeUpdate = (NodeUpdate *) hint;
      InvalidateNodeRec(nodeUpdate->node);
      swSetScrollSizes(_scroller, _lastXPosition, _maxYPosition);
      break;
      case UPDATE_ADD_ROUTE:
      case UPDATE_DELETE_ROUTE:
      routeUpdate = (RouteUpdate *) hint;
      InvalidateRoute(GetSocketPosition(routeUpdate->src,
                                routeUpdate->eventOut, 1), 
                    GetSocketPosition(routeUpdate->dest,
                                routeUpdate->eventIn, 0)
                      - Point(SOCKET_WIDTH / 2, 0));
      break;
      case UPDATE_MODE:
      case UPDATE_TIME:
      break;
    }
}

Point SceneGraphView::GetSocketPosition(Node *node, int socket, int side) const
{
    int         x, y, width, height;
    
    getZoomGraphPosition(x, y, node);
    getZoomGraphSize(width, height, node);
    y += (BORDER_WIDTH + ((SOCKET_SPACING + SOCKET_HEIGHT) * 
                          (2 * socket + 1)) / 2) * _zoom;
    if (side == 0) { // left
      x += (BORDER_WIDTH + SOCKET_SPACING + SOCKET_WIDTH / 2) * _zoom;
    } else {
      x += width - (BORDER_WIDTH + SOCKET_SPACING  + SOCKET_WIDTH / 2)
                     * _zoom;
    }
    return Point(x, y);
}

SBITMAP
SceneGraphView::LoadSocketBitmap(int id, int color)
{
    int mapFrom[4] = { 0x808000, 0x000000, 0xC0C0C0, 0x808080 };
    int mapTo[4] = { _face,
      SW_RGB(SW_RED(color) / 3, SW_GREEN(color) / 3, SW_BLUE(color) / 3),
      SW_RGB(MIN(SW_RED(color) + 128, 255),
             MIN(SW_GREEN(color) + 128, 255),
           MIN(SW_BLUE(color) + 128, 255)),
           color
    };

    return swLoadMappedBitmap(_window, id, mapFrom, mapTo, 4);
}

void
SceneGraphView::BuildSocketBitmaps()
{
    _typeColors[SFBOOL]     = 0x7F7F7F;

    _typeColors[SFCOLOR]    = 0x2F4FCF;
    _typeColors[MFCOLOR]    = 0x3F3F7F;

    _typeColors[SFIMAGE]    = 0xCF3FCF;

    _typeColors[SFINT32]    = 0x00FFFF;
    _typeColors[MFINT32]    = 0x007F7F;

    _typeColors[SFFLOAT]    = 0xCFCFFF;
    _typeColors[MFFLOAT]    = 0x5F5F7F;

    _typeColors[SFNODE]     = 0xFF1F7F;
    _typeColors[MFNODE]     = 0xCF005F;

    _typeColors[SFROTATION] = 0xCF00CF;
    _typeColors[MFROTATION] = 0x7F007F;

    _typeColors[SFSTRING]   = 0xCFCF00;
    _typeColors[MFSTRING]   = 0x7F7F00;

    _typeColors[SFTIME]     = 0xCF5F00;
    _typeColors[MFTIME]     = 0x7F5F00;

    _typeColors[SFVEC2F]    = 0x1F7F7F;
    _typeColors[MFVEC2F]    = 0x005F5F;

    _typeColors[SFVEC3F]    = 0xFF0000;
    _typeColors[MFVEC3F]    = 0x7F4F4F;

    _typeColors[LAST_TYPE + 1] = 0xFFFFFF;

    for (int i = 0; i < LAST_TYPE +2 ; i++) {
      _socketBitmaps[i] = LoadSocketBitmap(IDB_FULL_SOCKET, _typeColors[i]);
    }
}

int SceneGraphView::OnTimer() 
{
    int     sx, sy;
    int     w, h, vw, vh;

    swGetScrollPosition(_scroller, &sx, &sy);
    swGetSize(_window, &w, &h);
    swGetScrollViewportSize(_scroller, &vw, &vh);
    sx += _autoScrollDX;
    if (sx >= w - vw) sx = w - vw;
    if (sx < 0) sx = 0;
    sy += _autoScrollDY;
    if (sy >= h - vh) sy = h - vh;
    if (sy < 0) sy = 0;
    if (sy > MAX_Y) sy = MAX_Y;
    if (sy > _maxYPosition) sy = _maxYPosition;
    swSetScrollPosition(_scroller, sx, sy);
    DoMouseMove(_autoScrollPX + sx, _autoScrollPY + sy, 0);
    return TRUE;  // continue timer
}

void
SceneGraphView::getZoomGraphPosition(int &width, int &height, Node *node) const
{
    float w, h;
    node->getGraphPosition(&w, &h);
    width = (int) w * _zoom; 
    height = (int) h * _zoom; 
}

void
SceneGraphView::setZoomGraphPosition(Node *node, int x, int y)
{
    node->setGraphPosition(x / _zoom, y / _zoom);
}

void
SceneGraphView::getZoomGraphSize(int &width, int &height, Node *node) const
{
    node->getGraphSize(&width, &height);
    width *= _zoom; 
    if (width == 0)
        width = 1;
    height *= _zoom; 
    if (height == 0)
        height = 1;
}

void
SceneGraphView::setGraphSize(Node *node, int width, int height)
{
    node->setGraphSize(width, height);
}

void
SceneGraphView::zoomIn(void)
{ 
    if (_zoom >= 1.0) { 
        _zoom = 1.0;
        return;
    }
    _lastXPosition *= 2;
    _maxYPosition *= 2;
    _zoom *= 2.0; 
    int sx, sy;
    swGetScrollPosition(_scroller, &sx, &sy);
    swSetScrollSizes(_scroller, _lastXPosition, _maxYPosition);
    swSetScrollPosition(_scroller, sx * 2, sy * 2);
    swInvalidateWindow(_window);
}

void
SceneGraphView::zoomOut(void)
{ 
    _lastXPosition /= 2;
    _maxYPosition /= 2;
    _zoom /= 2.0; 
    int sx, sy;
    swGetScrollPosition(_scroller, &sx, &sy);
    swSetScrollSizes(_scroller, _lastXPosition, _maxYPosition);
    swSetScrollPosition(_scroller, sx / 2, sy / 2);
    swInvalidateWindow(_window);
}

void
SceneGraphView::unZoom(void)
{ 
    _lastXPosition /= _zoom;
    _maxYPosition /= _zoom;
    _zoom = 1.0; 
    jumpToSelection();
    swSetScrollSizes(_scroller, _lastXPosition, _maxYPosition);
    swInvalidateWindow(_window);
}

void
SceneGraphView::jumpToSelection(void)
{
    const Path *sel = _scene->getSelection();
    Node *current = sel ? sel->getNode() : NULL;
    if (current == NULL) 
        return;
    if (current == _scene->getRoot())
        return;
    int sx, sy;
    getZoomGraphPosition(sx, sy, current);
    int width, height;
    swGetScrollViewportSize(_scroller, &width, &height);
    sx = sx - width / 2;
    if (sx < 0)
        sx = 0;
    sy = sy - height  / 2;
    if (sy < 0)
        sy = 0;
    swSetScrollPosition(_scroller, sx, sy);
}




Generated by  Doxygen 1.6.0   Back to index