/*
* Copyright (c) 1997 by the University of Southern California
* All rights reserved.
*
* Permission to use, copy, modify, and distribute this software and its
* documentation in source and binary forms for non-commercial purposes
* and without fee is hereby granted, provided that the above copyright
* notice appear in all copies and that both the copyright notice and
* this permission notice appear in supporting documentation. and that
* any documentation, advertising materials, and other materials related
* to such distribution and use acknowledge that the software was
* developed by the University of Southern California, Information
* Sciences Institute. The name of the University may not be used to
* endorse or promote products derived from this software without
* specific prior written permission.
*
* THE UNIVERSITY OF SOUTHERN CALIFORNIA makes no representations about
* the suitability of this software for any purpose. THIS SOFTWARE IS
* PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*
* Other copyrights might apply to parts of this software and are so
* noted when applicable.
*
* $Header: /cvsroot/nsnam/nam-1/editview.cc,v 1.34 2003/10/11 22:56:49 xuanc Exp $
*/
#include <stdlib.h>
#ifdef WIN32
#include <windows.h>
#endif
#include <ctype.h>
#include <math.h>
#include "view.h"
#include "bbox.h"
#include "netmodel.h"
#include "editview.h"
#include "tclcl.h"
#include "paint.h"
#include "tag.h"
#include "node.h"
#include "edge.h"
#include "agent.h"
void EditView::DeleteCmdProc(ClientData cd)
{
EditView *ev = (EditView *)cd;
if (ev->tk_ != NULL) {
Tk_DestroyWindow(ev->tk_);
}
}
//----------------------------------------------------------------------
//----------------------------------------------------------------------
EditView::EditView(const char *name, NetModel* m)
: NetView(name), defTag_(NULL)
{
if (tk_!=0) {
Tcl& tcl = Tcl::instance();
cmd_ = Tcl_CreateCommand(tcl.interp(), Tk_PathName(tk_),
command,
(ClientData)this, DeleteCmdProc);
}
char str[256];
model_ = m;
sprintf(str, "def%-u", (intptr_t)this);
defTag_ = new Tag(str);
model_->add_tag(defTag_);
editing_stage_ = NONE;
}
//----------------------------------------------------------------------
// EditView::EditView(const char *name, NetModel* m,
// int width, int height)
//----------------------------------------------------------------------
EditView::EditView(const char *name, NetModel* m, int width, int height)
: NetView(name, SQUARE, width, height), defTag_(NULL) {
char str[256];
if (tk_!=0) {
Tcl& tcl = Tcl::instance();
cmd_ = Tcl_CreateCommand(tcl.interp(), Tk_PathName(tk_),
command, (ClientData) this,
DeleteCmdProc);
}
model_ = m;
sprintf(str, "def%-u", (intptr_t)this);
defTag_ = new Tag(name);
model_->add_tag(defTag_);
editing_stage_ = NONE;
}
EditView::~EditView()
{
model_->remove_view(this);
if (defTag_ != NULL) {
model_->delete_tag(defTag_->name());
delete defTag_;
defTag_ = NULL;
}
// Delete Tcl command created
// Tcl& tcl = Tcl::instance();
// Tcl_DeleteCommandFromToken(tcl.interp(), cmd_);
}
//----------------------------------------------------------------------
// int
// EditView::command(ClientData cd, Tcl_Interp* tcl,
// int argc, char **argv)
// Parse Tcl command interface
// - setPoint, addNode, addLink addAgent, deleteObject, etc...
//----------------------------------------------------------------------
int EditView::command(ClientData cd, Tcl_Interp* tcl,
int argc, CONST84 char **argv) {
EditorNetModel * editor_net_model;
Node * node, * source, * destination;
Edge * edge;
Agent * source_agent, * destination_agent;
TrafficSource * traffic_source;
LossModel * loss_model;
//double world_x, world_y;
if (argc < 2) {
Tcl_AppendResult(tcl, "\"", argv[0], "\": arg mismatch", 0);
return (TCL_ERROR);
}
char c = argv[1][0];
int length = strlen(argv[1]);
EditView * ev = (EditView *) cd;
editor_net_model = (EditorNetModel *) ev->model_;
float cx, cy;
int flag;
// Following implements several useful interactive commands of
// Tk's canvas. Their syntax and semantics are kept as close to
// those of Tk canvas as possible.
if ((c == 'd') && (strncmp(argv[1], "draw", length) == 0)) {
// Redraw seen at time = argv[2]
ev->draw(strtod(argv[2],NULL));
return TCL_OK;
} else if ((c == 'c') && (strncmp(argv[1], "close", length) == 0)) {
ev->destroy();
return TCL_OK;
} else if ((c == 'd') &&
(strncmp(argv[1], "dctag", length) == 0)) {
/*
* <view> dctag
*
* Delete the current selection, start all over.
*/
if (ev->defTag_ != NULL)
ev->defTag_->remove();
ev->draw();
return (TCL_OK);
} else if ((c == 's') &&
(strncmp(argv[1], "setPoint", length) == 0)) {
/*
* <view> setPoint x y addFlag
*
* Select the object (if any) under point (x, y). If no such
* object, set current point to (x, y)
*/
if (argc != 5) {
Tcl_AppendResult(tcl, "wrong # args: should be \"",
argv[0], " setPoint x y addFlag\"",
(char *)NULL);
return (TCL_ERROR);
}
cx = strtod(argv[2], NULL);
cy = strtod(argv[3], NULL);
flag = strtol(argv[4], NULL, 10);
return ev->cmdSetPoint(cx, cy, flag);
} else if ((c == 'd') && (strncmp(argv[1], "deleteObject", length) == 0)) {
cx = strtod(argv[2], NULL);
cy = strtod(argv[3], NULL);
return ev->cmdDeleteObj(cx, cy);
} else if ((c == 'm') && (strncmp(argv[1], "moveTo", length) == 0)) {
/*
* <view> moveto x y
*
* Move the current selected object (if any) or the
* rubber band to point (x, y)
*/
if (argc != 4) {
Tcl_AppendResult(tcl, "wrong # args: should be \"",
argv[0],
" moveTo x y\"", (char *)NULL);
return (TCL_ERROR);
}
cx = strtod(argv[2], NULL);
cy = strtod(argv[3], NULL);
return ev->cmdMoveTo(cx, cy);
} else if ((c == 'r') && (strncmp(argv[1], "releasePoint", length) == 0)) {
/*
* <view> releasePoint x y
*
* If any object is selected, set the object's
* position to point (x,y); otherwise set the rubber
* band rectangle and select all the objects in that
* rectangle Note: we need a default tag for the
* selection in rubber band.
*/
if (argc != 4) {
Tcl_AppendResult(tcl, "wrong # args: should be \"",
argv[0],
" releasePoint x y\"", (char *)NULL);
return (TCL_ERROR);
}
cx = strtod(argv[2], NULL);
cy = strtod(argv[3], NULL);
return ev->cmdReleasePoint(cx, cy);
} else if ((c == 's') && (strncmp(argv[1], "setNodeProperty", length) == 0)) {
// <view> setNodeProperty nodeid nodepropertyvalue properyname
int nodeid = atoi(argv[2]);
return ev->cmdsetNodeProperty(nodeid, argv[3], argv[4]);
} else if ((c == 's') && (strncmp(argv[1], "setAgentProperty", length) == 0)) {
// <view> setAgentProperty nodeid nodepropertyvalue properyname
int agentid = atoi(argv[2]);
return ev->cmdsetAgentProperty(agentid, argv[3], argv[4]);
} else if ((c == 's') && (strncmp(argv[1], "setLinkProperty", length) == 0)) {
// <view> setLinkProperty sid did propertyvalue properyname
int source_id = atoi(argv[2]);
int destination_id = atoi(argv[3]);
return ev->cmdsetLinkProperty(source_id, destination_id,
argv[4], argv[5]);
} else if ((c == 's') &&
(strncmp(argv[1], "setQueueHandleProperty", length) == 0)) {
// Called by the following code in Editor.tcl
// ------------------------------------------------------------
// $editor_view_ setQueueHandleProperty $source $destination
// $property_value
// $property_variable
//
// - argv[2] = source
// - argv[3] = destination
// - argv[4] = value
// - argv[5] = variable name
editor_net_model->setQueueHandleProperty(atoi(argv[2]), atoi(argv[3]),
argv[4], argv[5]);
ev->draw();
return TCL_OK;
} else if ((c == 's') &&
(strncmp(argv[1], "setTrafficSourceProperty", length) == 0)) {
// <view> setTrafficSourceProperty id propertyvalue propertyname
int id = atoi(argv[2]);
const char * value = argv[3];
const char * variable_name = argv[4];
return ev->cmdsetTrafficSourceProperty(id, value, variable_name);
} else if ((c == 's') &&
(strncmp(argv[1], "setLossModelProperty", length) == 0)) {
// <view> setLossModelProperty id propertyvalue propertyname
int id = atoi(argv[2]);
const char * value = argv[3];
const char * variable_name = argv[4];
return ev->cmdsetLossModelProperty(id, value, variable_name);
} else if ((c == 'a') && (strncmp(argv[1], "addNode", length) == 0)) {
// <view> addNode x y
// - add a new Node under current (x,y) with default size
cx = strtod(argv[2], NULL);
cy = strtod(argv[3], NULL);
return ev->cmdaddNode(cx, cy);
} else if ((c == 'i') && (strncmp(argv[1], "importNode", length) == 0)) {
// Used when reading a nam editor file to add a node created in tcl
// to this editview and its editornetmodel
node = (Node *) TclObject::lookup(argv[2]);
//world_x = atof(argv[3]);
//world_y = atof(argv[4]);
if (node) {
if (editor_net_model->addNode(node)) {
// node->place(world_x, world_y);
// ev->draw();
return TCL_OK;
}
}
fprintf(stderr, "Error creating node.\n");
return TCL_ERROR;
} else if ((c == 'a') && (strncmp(argv[1], "attachNodes", length) == 0)) {
// <view> linkNodes source_id destination_id
// - link 2 existing nodes to each other
edge = (Edge *) TclObject::lookup(argv[2]);
source = (Node *) TclObject::lookup(argv[3]);
destination = (Node *) TclObject::lookup(argv[4]);
edge->attachNodes(source, destination);
editor_net_model->addEdge(edge);
ev->draw();
return TCL_OK;
} else if ((c == 'a') && (strncmp(argv[1], "addLink", length) == 0)) {
// <view> addLink x y
// - add a new Link if its start AND end point is inside of
cx = strtod(argv[2], NULL);
cy = strtod(argv[3], NULL);
return ev->cmdaddLink(cx, cy);
} else if ((c == 'a') && (strncmp(argv[1], "addQueueHandle", length) == 0)) {
// <view> addQueueHandle edge queue_type
edge = (Edge *) TclObject::lookup(argv[2]);
if (edge) {
editor_net_model->addQueueHandle(edge, argv[3]);
}
return TCL_OK;
// --------------- Agent -----------------
} else if ((c == 'a') && (strncmp(argv[1], "addAgent", length) == 0)) {
// <view> addAgent x y agent
// - add a new agent
cx = strtod(argv[2], NULL);
cy = strtod(argv[3], NULL);
const char * agent_name = argv[4];
return ev->cmdaddAgent(cx, cy, agent_name);
} else if ((c == 'i') && (strncmp(argv[1], "importAgent", length) == 0)) {
source_agent = (Agent *) TclObject::lookup(argv[2]);
node = (Node *) TclObject::lookup(argv[3]);
return editor_net_model->addAgent(source_agent, node);
} else if ((c == 'l') && (strncmp(argv[1], "linkAgents", length) == 0)) {
// <view> linkAgents source_id destination_id
// - link 2 existing agents to each other
source_agent = (Agent *) TclObject::lookup(argv[2]);
destination_agent = (Agent *) TclObject::lookup(argv[3]);
return editor_net_model->addAgentLink(source_agent, destination_agent);
} else if ((c == 's') && (strncmp(argv[1], "showAgentLink", length) == 0)) {
cx = strtod(argv[2], NULL);
cy = strtod(argv[3], NULL);
return ev->showAgentLink(cx, cy);
} else if ((c == 'h') && (strncmp(argv[1], "hideAgentLinks", length) == 0)) {
editor_net_model->hideAgentLinks();
ev->draw();
return TCL_OK;
// --------------- Traffic Source -----------------
} else if ((c == 'a') &&
(strncmp(argv[1], "addTrafficSource", length) == 0)) {
// <view> addTrafficSource x y trafficsource_type
// - add a new TrafficSource
cx = strtod(argv[2], NULL);
cy = strtod(argv[3], NULL);
// argv[4] is the name of the traffic source
return ev->cmdaddTrafficSource(cx, cy, argv[4]);
} else if ((c == 'a') &&
(strncmp(argv[1], "attachTrafficSource", length) == 0)) {
traffic_source = (TrafficSource *) TclObject::lookup(argv[2]);
source_agent = (Agent *) TclObject::lookup(argv[3]);
return editor_net_model->addTrafficSource(traffic_source, source_agent);
// ----------- Loss Models ----------------
} else if ((c == 'a') &&
(strncmp(argv[1], "addLossModel", length) == 0)) {
// <view> addLossModel x y lossmodel
cx = strtod(argv[2], NULL);
cy = strtod(argv[3], NULL);
// argv[4] is the type of the loss model to add
return ev->cmdaddLossModel(cx, cy, argv[4]);
} else if ((c == 'a') &&
(strncmp(argv[1], "attachLossModel", length) == 0)) {
loss_model = (LossModel *) TclObject::lookup(argv[2]);
source = (Node *) TclObject::lookup(argv[3]);
destination = (Node *) TclObject::lookup(argv[4]);
edge = source->find_edge(destination->number());
return editor_net_model->addLossModel(loss_model, edge);
// ----------- Object and Object Properties ----------------
} else if ((c == 'g') &&
(strncmp(argv[1], "getObjectInformation", length) == 0)) {
// <view> getObject x y
// - return object under current point
cx = strtod(argv[2], NULL);
cy = strtod(argv[3], NULL);
return ev->cmdgetObjectInformation(cx, cy);
} else if ((c == 'g') &&
(strncmp(argv[1], "getObjectProperty", length) == 0)) {
// <view> getObjectPropert x y [type]
// - return properties for object under current point
// - if type is passed in then pass that to object
cx = strtod(argv[2], NULL);
cy = strtod(argv[3], NULL);
if (argc == 5) {
return ev->cmdgetObjectProperties(cx, cy, argv[4]);
} else {
return ev->cmdgetObjProperty(cx, cy);
}
} else if ((c == 'v') && (strncmp(argv[1], "view_mode", length)==0)) {
/*
* <view> view_mode
*
* clear defTag_ and change to view mode
*/
ev->view_mode();
return TCL_OK;
}
return (NetView::command(cd, tcl, argc, argv));
}
int EditView::cmdsetNodeProperty(int id, const char * value, const char * variable)
{
EditorNetModel* emodel_ = (EditorNetModel *) model_;
// goto enetmodel.cc
emodel_->setNodeProperty(id, value, variable);
// EditType oldt_;
// oldt_ = editing_stage_;
// editing_stage_ = END_OBJECT;
draw();
// editing_stage_ = NONE;
// model_->update(model_->now());
// editing_stage_ = oldt_;
return(TCL_OK);
}
int EditView::cmdsetAgentProperty(int id, const char * value, const char * variable) {
EditorNetModel* emodel_ = (EditorNetModel *) model_;
emodel_->setAgentProperty(id, value ,variable);
draw();
return(TCL_OK);
}
int EditView::cmdsetLinkProperty(int sid, int did,
const char * value, const char * variable) {
EditorNetModel * emodel_ = (EditorNetModel *) model_;
emodel_->setLinkProperty(sid, did, value, variable);
draw();
return(TCL_OK);
}
//----------------------------------------------------------------------
// int
// EditView::cmdsetTrafficSourceProperty(int sid, int did, const char *pv, int pn)
//----------------------------------------------------------------------
int
EditView::cmdsetTrafficSourceProperty(int id, const char * value, const char * variable) {
EditorNetModel* emodel_ = (EditorNetModel *) model_;
emodel_->setTrafficSourceProperty(id, value, variable);
draw();
return(TCL_OK);
}
//----------------------------------------------------------------------
// int
// EditView::cmdsetLossModelProperty(int id, char * value, char * variable)
//----------------------------------------------------------------------
int
EditView::cmdsetLossModelProperty(int id, const char * value, const char * variable) {
EditorNetModel* emodel_ = (EditorNetModel *) model_;
emodel_->setLossModelProperty(id, value, variable);
draw();
return(TCL_OK);
}
//----------------------------------------------------------------------
// int
// EditView::cmdgetObjProperty(float cx, float cy)
// - get properties for a selected object
//----------------------------------------------------------------------
int
EditView::cmdgetObjProperty(float cx, float cy) {
Animation *p;
Tcl& tcl = Tcl::instance();
// matrix_ comes from class View (view.h)
// - imap is the inverse mapping
// (i.e from screen to world coordinate systems)
matrix_.imap(cx, cy);
// Finds the object which contains the coordinate (cx, cy)
p = model_->inside(cx, cy);
if (p == NULL) {
tcl.resultf("NONE");
} else {
tcl.resultf("%s",p->property());
}
return(TCL_OK);
}
//----------------------------------------------------------------------
// int
// EditView::cmdgetObjectProperties(float cx, float cy, char * type)
// - get properties for a selected object and the specific
// type within that object
//----------------------------------------------------------------------
int
EditView::cmdgetObjectProperties(float cx, float cy, const char * type) {
Animation * animation_object;
Tcl& tcl = Tcl::instance();
// matrix_ comes from class View (view)
// - imap is the inverse mapping
// (i.e from screen to world coordinate systems)
matrix_.imap(cx, cy);
// Finds the object which contains the coordinate (cx, cy)
animation_object = model_->inside(cx, cy);
if (animation_object == NULL) {
tcl.resultf("NONE");
} else {
tcl.resultf("%s",animation_object->getProperties(type));
}
return(TCL_OK);
}
//----------------------------------------------------------------------
//----------------------------------------------------------------------
int EditView::cmdgetObjectInformation(float cx, float cy) {
Tcl& tcl = Tcl::instance();
matrix_.imap(cx, cy);
Animation *p = model_->inside(cx, cy);
if (p == NULL) {
tcl.resultf("NONE");
} else {
tcl.resultf("%s",p->info());
}
return(TCL_OK);
}
//----------------------------------------------------------------------
// int
// EditView::cmdaddLink(float cx, float cy)
// - Note: all cx_ and cy_ below are in *window* coordinates
//----------------------------------------------------------------------
int
EditView::cmdaddLink(float cx, float cy) {
Animation * p;
static Animation * old_p;
EditorNetModel* emodel_ = (EditorNetModel *) model_;
cx_ = cx;
cy_ = cy;
matrix_.imap(cx, cy);
// Do we have a node on current point ?
p = model_->inside(cx, cy);
if (p == NULL) {
defTag_->remove();
if (editing_stage_ == START_LINK) {
editing_stage_ = NONE;
draw();
}
return (TCL_OK);
}
if (p->classid() == ClassNodeID) {
if (editing_stage_ != START_LINK) {
old_p = p; /* remember the orig node */
startSetObject(p, cx_, cy_);
editing_stage_ = START_LINK;
} else if ((old_p == p)||(old_p->classid()!=ClassNodeID)) {
editing_stage_ = NONE;
draw();
// to support making link by click-&-click
editing_stage_ = START_LINK;
} else {
// add a new link b/w the two nodes
startSetObject(p, cx_, cy_);
Node *src, *dst;
src = (Node *)old_p;
dst = (Node *)p;
emodel_->addLink(src, dst);
editing_stage_ = END_OBJECT;
// Erase old positions
defTag_->draw(this, model_->now());
// At least we should redo scale estimation and
// place everything
defTag_->move(this, rb_.xmax - oldx_, rb_.ymax - oldy_);
model_->recalc();
model_->render(this);
defTag_->remove();
editing_stage_ = NONE;
draw();
editing_stage_ = NONE;
}
} else if (p->classid() == ClassAgentID) {
if (editing_stage_ != START_LINK) {
old_p = p;
startSetObject(p, cx_, cy_);
editing_stage_ = START_LINK;
} else if ((old_p == p)||(old_p->classid()!= ClassAgentID)) {
editing_stage_ = NONE;
draw();
// to support making agent-link by click-&-click
editing_stage_ = START_LINK;
} else {
startSetObject(p, cx_, cy_);
Agent *src_agent, *dst_agent;
src_agent = (Agent *)old_p;
dst_agent = (Agent *)p;
emodel_->addAgentLink(src_agent, dst_agent);
editing_stage_ = END_OBJECT;
defTag_->draw(this, model_->now());
defTag_->move(this, rb_.xmax - oldx_, rb_.ymax - oldy_);
model_->recalc();
model_->render(this);
defTag_->remove();
editing_stage_ = NONE;
draw();
}
} else {
editing_stage_ = NONE;
}
return(TCL_OK);
}
//----------------------------------------------------------------------
// int
// EditView::cmdaddAgent(float cx, float cy, char* agent)
//----------------------------------------------------------------------
int EditView::cmdaddAgent(float cx, float cy, const char* agent) {
Animation * p;
Node * src;
EditorNetModel* emodel_ = (EditorNetModel *)model_;
// Switch from screen coordinates to world coordinates
matrix_.imap(cx, cy);
// Do we have a node on the clicked point ?
p = model_->inside(cx, cy);
if (p == NULL) {
defTag_->remove();
return (TCL_OK);
}
if (p->classid() == ClassNodeID) {
// Yes, we have a node to which we can add the agent
src = (Node *) p;
// goto EditorNetModel::addAgent(...) in enetmodel.cc
emodel_->addAgent(src, agent, cx, cy);
draw();
} else {
return (TCL_OK);
}
return(TCL_OK);
}
//----------------------------------------------------------------------
// int EditView::showAgentLink(float cx, float cy)
//----------------------------------------------------------------------
int EditView::showAgentLink(float cx, float cy) {
Animation * animation;
Agent * agent;
// Change from screen coordinates to worl coordinates
matrix_.imap(cx, cy);
// Get the clicked on animation object.
animation = model_->inside(cx, cy);
if (animation != NULL && animation->classid() == ClassAgentID) {
agent = (Agent *) animation;
agent->showLink();
draw();
}
return(TCL_OK);
}
//----------------------------------------------------------------------
// int
// EditView::cmdaddNode(float cx, float cy)
// Note: all cx_ and cy_ below are in *window* coordinates
//----------------------------------------------------------------------
int EditView::cmdaddNode(float cx, float cy) {
Animation * animation_object;
EditorNetModel* emodel_ = (EditorNetModel *)model_;
// Convert screen coordinates to world coordinates
matrix_.imap(cx, cy);
// Check to see if an object already exists on the click point
animation_object = model_->inside(cx,cy);
if (animation_object == NULL) {
defTag_->remove();
emodel_->addNode(cx, cy);
draw();
}
return(TCL_OK);
}
//----------------------------------------------------------------------
// int
// EditView::cmdDeleteObj(float cx, float cy)
//----------------------------------------------------------------------
int
EditView::cmdDeleteObj(float cx, float cy) {
Animation * p; // I don't know why p was chosen for the varible name
// Just to confuse other programmers, I guess
// First of all, clear the old point
cx_ = cx;
cy_ = cy;
// Do we have an animation object on the clicked point?
matrix_.imap(cx, cy);
p = model_->inside(cx, cy);
if (p == NULL) {
defTag_->remove();
return (TCL_OK);
}
// If object is already selected unselect it
if (p->isTagged()) {
if (p->numTag() > 1) {
fprintf(stderr, "Error: More than one tag for an object %d!\n",
p->id());
p = NULL;
} else {
p = p->getLastTag();
}
}
// Only nodes, links, agents, traffic sources and
// loss models can be deleted
if ((p->classid() != ClassNodeID) &&
(p->classid() != ClassEdgeID) &&
(p->classid() != ClassAgentID) &&
(p->classid() != ClassTrafficSourceID) &&
(p->classid() != ClassLossModelID)) {
p = NULL;
}
if (p == NULL) {
defTag_->remove();
} else {
if (p->classid() == ClassNodeID) {
Node * n = (Node *) p;
EditorNetModel * emodel_ = (EditorNetModel *) model_;
emodel_->removeNode(n);
draw();
}
if (p->classid() == ClassEdgeID) {
Edge * e = (Edge *) p;
EditorNetModel * emodel_ = (EditorNetModel *) model_;
emodel_->removeLink(e);
draw();
}
if (p->classid() == ClassAgentID) {
Agent * a = (Agent *) p;
EditorNetModel* emodel_ = (EditorNetModel *) model_;
emodel_->removeAgent(a);
draw();
}
if (p->classid() == ClassTrafficSourceID) {
TrafficSource * ts = (TrafficSource *) p;
EditorNetModel* emodel_ = (EditorNetModel *) model_;
emodel_->removeTrafficSource(ts);
draw();
}
if (p->classid() == ClassLossModelID) {
LossModel * lossmodel = (LossModel *) p;
EditorNetModel* emodel_ = (EditorNetModel *) model_;
emodel_->removeLossModel(lossmodel);
draw();
}
}
return (TCL_OK);
}
//----------------------------------------------------------------------
// int
// EditView::cmdaddTrafficSource(float cx, float cy, char * type)
//----------------------------------------------------------------------
int
EditView::cmdaddTrafficSource(float cx, float cy, const char * type) {
Animation * object;
Agent * agent;
EditorNetModel* emodel_ = (EditorNetModel *)model_;
// Switch from screen coordinates to world coordinates
matrix_.imap(cx, cy);
// Do we have an agent on the clicked point ?
object = model_->inside(cx, cy);
if (object == NULL) {
defTag_->remove();
return (TCL_OK);
}
if (object->classid() == ClassAgentID) {
// Yes, we have a node to which we can add the agent
agent = (Agent *) object;
// goto EditorNetModel::addTrafficSource(...) in enetmodel.cc
emodel_->addTrafficSource(agent, type, cx, cy);
draw();
} else {
return (TCL_OK);
}
return(TCL_OK);
}
//----------------------------------------------------------------------
// int
// EditView::cmdaddLossModel(float cx, float cy, char * type)
//----------------------------------------------------------------------
int
EditView::cmdaddLossModel(float cx, float cy, const char * type) {
Animation * object;
Node * source, * destination;
Edge * edge, * reverse_edge;
EditorNetModel* emodel_ = (EditorNetModel *) model_;
// Switch from screen coordinates to world coordinates
matrix_.imap(cx, cy);
// Do we have a link on the clicked point ?
object = model_->inside(cx, cy);
if (object == NULL) {
defTag_->remove();
return (TCL_OK);
}
if (object->classid() == ClassEdgeID ||
object->classid() == ClassQueueHandleID ) {
//
// Yes, we have a possible edge to which we can add the loss model
if (object->classid() == ClassQueueHandleID ) {
edge = ((QueueHandle *) object)->getEdge();
} else {
edge = (Edge *) object;
}
if (edge) {
// Check distance to source to determine if we should attach
// to the forward or reverse edge
source = edge->getSourceNode();
destination = edge->getDestinationNode();
if (source->distance(cx, cy) > destination->distance(cx,cy)) {
// if source is farther away than destination then place
// this loss model on the reverse edge
reverse_edge = emodel_->lookupEdge(destination->number(), source->number());
if (reverse_edge) { // Make sure there is a reverse edge
edge = reverse_edge;
}
}
// goto EditorNetModel::addTrafficSource(...) in enetmodel.cc
emodel_->addLossModel(edge, type, cx, cy);
draw();
}
}
return(TCL_OK);
}
// ---------------------------------------------------------------------
// int
// EditView::cmdSetPoint(float cx, float cy, int bAdd)
// - Note: all cx_ and cy_ below are in *window* coordinates
// ---------------------------------------------------------------------
int
EditView::cmdSetPoint(float cx, float cy, int add_object) {
Animation * animation_object;
// First of all, clean the old group
cx_ = cx;
cy_ = cy;
// Inverse Map cx, cy to world coordinates
matrix_.imap(cx, cy);
// Do we have anything on current point?
animation_object = model_->inside(cx, cy);
// If nothing at this point start selection rubberband
if (animation_object == NULL) {
defTag_->remove();
startRubberBand(cx_, cy_);
return (TCL_OK);
}
// Otherwise look to move object if it is a node or a Tag
// - A tag is a grouping marker, if an object is tagged then
// that tag group can be moved together
if (animation_object->isTagged()) {
if (animation_object->numTag() > 1) {
fprintf(stderr, "Error: More than one tag for object %d!\n",
animation_object->id());
animation_object = NULL;
} else {
animation_object = animation_object->getLastTag();
}
}
// Only nodes and tags can be moved
if ((animation_object->classid() == ClassNodeID) ||
(animation_object->classid() == ClassTagID)) {
// If a single non-tag object is selected, or explicitly
// instructed, remove the previous selection. Otherwise,
// the object under the current point will be added to the
// entire tagged selection
if (!add_object && (animation_object != defTag_)) {
defTag_->remove();
}
// Just tags the object as being selected.
// Draws a box around the tagged object
startSetObject(animation_object, cx_, cy_);
} else {
defTag_->remove();
startRubberBand(cx_, cy_);
}
return (TCL_OK);
}
//----------------------------------------------------------------------
// int
// EditView::cmdMoveTo(float cx, float cy)
// - Moves object to end location
// - Ends the rubber band selection
//----------------------------------------------------------------------
int EditView::cmdMoveTo(float cx, float cy) {
// cx and cy should be in screen (canvas) coordinates
cx_ = cx;
cy_ = cy;
switch (editing_stage_) {
case START_RUBBERBAND:
case MOVE_RUBBERBAND:
oldx_ = rb_.xmax;
oldy_ = rb_.ymax;
rb_.xmax = cx_;
rb_.ymax = cy_;
editing_stage_ = MOVE_RUBBERBAND;
clip_ = rb_;
clip_.adjust();
if (clip_.xmin > oldx_)
clip_.xmin = oldx_;
if (clip_.xmax < oldx_)
clip_.xmax = oldx_;
if (clip_.ymin > oldy_)
clip_.ymin = oldy_;
if (clip_.ymax < oldy_)
clip_.ymax = oldy_;
break;
case START_OBJECT:
case MOVE_OBJECT: {
oldx_ = rb_.xmax;
oldy_ = rb_.ymax;
rb_.xmax = cx_;
rb_.ymax = cy_;
editing_stage_ = MOVE_OBJECT;
clip_.clear();
defTag_->merge(clip_);
matrix_.map(clip_.xmin, clip_.ymin);
matrix_.map(clip_.xmax, clip_.ymax);
clip_.adjust();
// Actual move and final bbox computation is done in render
break;
case START_LINK:
case MOVE_LINK:
// I believe this is never reached and should be removed
// maybe it is changed in the future
oldx_ = rb_.xmax;
oldy_ = rb_.ymax;
rb_.xmax = cx_;
rb_.ymax = cy_;
editing_stage_ = MOVE_LINK;
clip_ = rb_;
clip_.adjust();
if (clip_.xmin > oldx_)
clip_.xmin = oldx_;
if (clip_.xmax < oldx_)
clip_.xmax = oldx_;
if (clip_.ymin > oldy_)
clip_.ymin = oldy_;
if (clip_.ymax < oldy_)
clip_.ymax = oldy_;
break;
}
default:
// to avoid segmentation fault from click-n-dragging
return (TCL_OK);
}
draw();
return (TCL_OK);
}
int EditView::cmdReleasePoint(float cx, float cy) {
static char buffer[512];
int chars_written;
cx_ = cx;
cy_ = cy;
Tcl & tcl = Tcl::instance();
switch (editing_stage_) {
case START_RUBBERBAND:
case MOVE_RUBBERBAND: {
oldx_ = rb_.xmax; oldy_ = rb_.ymax;
rb_.xmax = cx_, rb_.ymax = cy_;
// Need to add the region to defTag_
clip_ = rb_;
clip_.adjust();
BBox bb = clip_;
matrix_.imap(bb.xmin, bb.ymin);
matrix_.imap(bb.xmax, bb.ymax);
bb.adjust();
model_->tagArea(bb, defTag_, 1);
// We can do a total redraw
editing_stage_ = NONE;
draw();
// Get time movement info for node markers on time slider
// defTag_->addNodeMovementDestination(this, cx - oldx_, cy - oldy_, model_->now());
// chars_written = defTag_->getNodeMovementTimes(buffer, 512);
// if (chars_written == -1) {
tcl.resultf("NONE");
// } else {
// tcl.resultf("%s", buffer);
// }
break;
}
case START_OBJECT:
case MOVE_OBJECT: {
oldx_ = rb_.xmax;
oldy_ = rb_.ymax;
rb_.xmax = cx_;
rb_.ymax = cy_;
clip_.clear();
defTag_->merge(clip_);
matrix_.map(clip_.xmin, clip_.ymin);
matrix_.map(clip_.xmax, clip_.ymax);
clip_.adjust();
// Later in render() we'll compute the real bbox
editing_stage_ = END_OBJECT;
draw();
editing_stage_ = NONE;
model_->update(model_->now());
// defTag_->move(this, rb_.xmax - oldx_, rb_.ymax - oldy_);
// Get time movement info for node markers on time slider
defTag_->addNodeMovementDestination(this, cx - oldx_, cy - oldy_, model_->now());
chars_written = defTag_->getNodeMovementTimes(buffer, 512);
if (chars_written == -1) {
tcl.resultf("NONE");
} else {
tcl.resultf("%s", buffer);
}
break;
}
case START_LINK:
case MOVE_LINK: {
editing_stage_ = START_LINK;
draw();
model_->update(model_->now());
cmdaddLink(cx_, cy_);
tcl.resultf("NONE");
break;
}
default:
// This cannot happen!
editing_stage_ = NONE;
draw();
tcl.resultf("NONE");
}
return (TCL_OK);
}
//----------------------------------------------------------------------
//----------------------------------------------------------------------
inline void
EditView::startRubberBand(float cx, float cy) {
// Nothing's here. Set rubber band.
editing_stage_ = START_RUBBERBAND;
rb_.xmin = rb_.xmax = cx;
rb_.ymin = rb_.ymax = cy;
clip_ = rb_;
}
//----------------------------------------------------------------------
//----------------------------------------------------------------------
inline void
EditView::startSetObject(Animation * animation_object, float cx, float cy) {
// Find an object, add it to group
editing_stage_ = START_OBJECT;
// Add it into defTag_
if (animation_object != defTag_) {
model_->tagObject(defTag_, animation_object);
}
rb_.xmin = rb_.xmax = cx;
rb_.ymin = rb_.ymax = cy;
clip_.clear();
defTag_->merge(clip_);
// for the bounding box (bbox)
oldx_ = rb_.xmax;
oldy_ = rb_.ymax;
rb_.xmax = cx_;
rb_.ymax = cy_;
clip_.clear();
defTag_->merge(clip_);
matrix_.map(clip_.xmin, clip_.ymin);
matrix_.map(clip_.xmax, clip_.ymax);
clip_.adjust();
// Later in render() we'll compute the real bbox
// We have selected the object and now we are at the end of
// the object selection process
editing_stage_ = END_OBJECT;
draw();
editing_stage_ = NONE;
model_->update(model_->now());
editing_stage_ = START_OBJECT;
}
//----------------------------------------------------------------------
// void EditView::draw()
//----------------------------------------------------------------------
void EditView::draw() {
if (editing_stage_ == NONE) {
View::draw();
} else {
// Ignore the cleaning part
render();
// XXX Don't understand why clip's height and width need to
// increase 3 to draw tagged objects correctly.
XCopyArea(Tk_Display(tk_), offscreen_, Tk_WindowId(tk_),
background_,(int)clip_.xmin, (int)clip_.ymin,
(int)clip_.width()+3, (int)clip_.height()+3,
(int)clip_.xmin, (int)clip_.ymin);
}
}
//----------------------------------------------------------------------
// void EditView::draw(double current_time)
//----------------------------------------------------------------------
void EditView::draw(double current_time) {
model_->update(current_time);
}
//----------------------------------------------------------------------
//----------------------------------------------------------------------
void EditView::xline(float x0, float y0, float x1, float y1, GC gc) {
XDrawLine(Tk_Display(tk_), offscreen_, gc, (int) x0, (int) y0,
(int) x1, (int) y1);
}
// Without transform.
void EditView::xrect(float x0, float y0, float x1, float y1, GC gc)
{
int x = (int) floor(x0);
int y = (int) floor(y0);
int w = (int)(x1 - x0);
if (w < 0) {
x = (int) ceil(x1);
w = -w;
}
int h = (int)(y1 - y0);
if (h < 0) {
h = -h;
y = (int)ceil(y1);
}
XDrawRectangle(Tk_Display(tk_), offscreen_, gc, x, y, w, h);
}
void EditView::line(float x0, float y0, float x1, float y1, int color)
{
if (editing_stage_ != NONE)
View::line(x0, y0, x1, y1, Paint::instance()->Xor());
else
View::line(x0, y0, x1, y1, color);
}
void EditView::rect(float x0, float y0, float x1, float y1, int color)
{
if (editing_stage_ != NONE)
View::rect(x0, y0, x1, y1, Paint::instance()->Xor());
else
View::rect(x0, y0, x1, y1, color);
}
void EditView::polygon(const float* x, const float* y, int n, int color)
{
if (editing_stage_ != NONE)
View::polygon(x, y, n, Paint::instance()->Xor());
else
View::polygon(x, y, n, color);
}
void EditView::fill(const float* x, const float* y, int n, int color)
{
if (editing_stage_ != NONE)
View::fill(x, y, n, Paint::instance()->Xor());
else
View::fill(x, y, n, color);
}
void EditView::circle(float x, float y, float r, int color)
{
if (editing_stage_ != NONE)
View::circle(x, y, r, Paint::instance()->Xor());
else
View::circle(x, y, r, color);
}
// Do not display any string, because no xor font gc
void EditView::string(float fx, float fy, float dim, const char* s, int anchor)
{
if (editing_stage_ == NONE)
View::string(fx, fy, dim, s, anchor);
}
//----------------------------------------------------------------------
// void
// EditView::BoundingBox(BBox &bb)
// - This copies the area in which an animation drawn may be drawn
// into (clipping area) the destination bb.
//----------------------------------------------------------------------
void
EditView::BoundingBox(BBox &bb) {
double temp;
// Calculate the world coordinates for the view's canvas
matrix_.imap(0.0, 0.0, bb.xmin, bb.ymin);
matrix_.imap(width_, height_, bb.xmax, bb.ymax);
// Check to make sure xmin, ymin is the lower left corner
// and xmax, ymax is the upper right
if (bb.xmin > bb.xmax) {
temp = bb.xmax;
bb.xmax = bb.xmin;
bb.xmin = temp;
}
if (bb.ymin > bb.ymax) {
temp = bb.ymax;
bb.ymax = bb.ymin;
bb.ymin = temp;
}
}
void
EditView::getWorldBox(BBox &bb) {
model_->BoundingBox(bb);
}
//----------------------------------------------------------------------
// void
// EditView::render()
// - not sure why this is called render but it seems to take care of
// rubberband selections and moving a selection on the screen
// - I believe the real "rendering" is done in model_->render()
// which is of type NetModel. -- mehringe@isi.edu
//
//----------------------------------------------------------------------
void
EditView::render() {
// Here we can compute the clipping box for render
Paint *paint = Paint::instance();
GC gc = paint->paint_to_gc(paint->Xor());
switch (editing_stage_) {
case START_RUBBERBAND:
// draw rubber band
xrect(rb_.xmin, rb_.ymin, rb_.xmax, rb_.ymax, gc);
break;
case MOVE_RUBBERBAND:
// erase previous rubberband
xrect(rb_.xmin, rb_.ymin, oldx_, oldy_, gc);
// draw new rubberband
xrect(rb_.xmin, rb_.ymin, rb_.xmax, rb_.ymax, gc);
break;
case END_RUBBERBAND:
// erase previous rubber band
xrect(rb_.xmin, rb_.ymin, oldx_, oldy_, gc);
// XXX Should draw the tag?
model_->render(this);
editing_stage_ = NONE;
break;
case START_OBJECT:
xrect(rb_.xmin, rb_.ymin, rb_.xmax, rb_.ymax, gc);
// xor-draw all relevant objects
defTag_->draw(this, model_->now());
break;
case MOVE_OBJECT:
// erase old positions first.
if ((oldx_ == rb_.xmax) && (oldy_ == rb_.ymax))
return;
defTag_->draw(this, model_->now());
// move these objects
defTag_->move(this, rb_.xmax - oldx_, rb_.ymax - oldy_);
BBox bb;
bb.clear();
defTag_->merge(bb);
matrix_.imap(bb.xmin, bb.ymin);
matrix_.imap(bb.xmax, bb.ymax);
bb.adjust();
clip_.merge(bb);
defTag_->draw(this, model_->now());
break;
case END_OBJECT:
// Erase old positions
defTag_->draw(this, model_->now());
// At least we should redo scale estimation and
// place everything
defTag_->move(this, rb_.xmax - oldx_, rb_.ymax - oldy_);
model_->recalc();
model_->render(this);
editing_stage_ = NONE;
break;
case START_LINK:
line(link_start_x_, link_start_y_, link_end_x_, link_end_y_, 3);
defTag_->draw(this, model_->now());
break;
case MOVE_LINK:
// erase previous link
xline(rb_.xmin, rb_.ymin, oldx_, oldy_, gc);
// draw new rubberband
xline(rb_.xmin, rb_.ymin, rb_.xmax, rb_.ymax, gc);
break;
case END_LINK:
// erase previous link
xline(rb_.xmin, rb_.ymin, oldx_, oldy_, gc);
// XXX Should draw the tag?
model_->render(this);
editing_stage_ = NONE;
break;
default:
// redraw model
model_->render(this);
break;
}
return;
}
syntax highlighted by Code2HTML, v. 0.9.1