// Copyright (C) 2001 Jean-Marc Valin #include "GUINode.h" #include "GUINetwork.h" #include "Node.h" #include "GUIDocument.h" #include "GUITerminal.h" #include "GUINodeParameters.h" #include "GUILink.h" #include "GUINetTerminal.h" #include "GUINodeTooltip.h" #include "flow_pref.h" #include #include #include "vflow.h" using namespace std; namespace FD { static gint node_handler (GnomeCanvasItem *item, GdkEvent *event, gpointer data) { return ((GUINode *)(data))->event(event); } int theTime; GUINode::GUINode(UINetwork* _net, string _name, string _type, double _x, double _y) : UINode(_net, _name, _type, _x, _y, false) , dragging(false) , grab(false) { parameters = newNodeParameters(this,type); initialize_widgets(); createPopup(); } GUINode::GUINode(UINetwork* _net, xmlNodePtr def) : UINode(_net, def,false), dragging(false) , grab(false) { //TODO use loadXML function instead of reimplementing xml loading here! //loadXML(def); char *str_name = (char *)xmlGetProp(def, (xmlChar *)"name"); char *str_type = (char *)xmlGetProp(def, (xmlChar *)"type"); char *str_x = (char *)xmlGetProp(def, (xmlChar *)"x"); char *str_y = (char *)xmlGetProp(def, (xmlChar *)"y"); if (!str_name || !str_type || !str_x || !str_y) { throw new GeneralException("Missing node parameter(s) in XML definition", __FILE__, __LINE__); } name = string(str_name); type = string(str_type); x = atof(str_x); y = atof(str_y); free (str_name); free (str_type); free(str_x); free(str_y); xtmp = x; ytmp = y; description = net->getDocument()->getDescription(type); parameters = newNodeParameters(this, type); initialize_widgets(); parameters->load(def); createPopup(); } GUINode::~GUINode() { dynamic_cast(net)->removeSelectedNode(this); for (int i=0;igetName()<getName()<removeNode(this); gtk_object_destroy(GTK_OBJECT(group)); destroyed=true; } /* static void node_add_input (GtkMenuItem *menuitem, GUINode *node) { char *input_name = "INTPUT-N"; node->addTerminal(string(input_name), UINetTerminal::INPUT); } static void node_add_output (GtkMenuItem *menuitem, GUINode *node) { char *output_name = "OUTPUT-N"; node->addTerminal(string(output_name), UINetTerminal::OUTPUT); } */ static void node_help (GtkMenuItem *menuitem, gpointer user_data) { ((GUINode *)(user_data))->help(); } static void node_prop (GtkMenuItem *menuitem, gpointer user_data) { ((GUINode *)(user_data))->propertiesShow(); } static void node_delete (GtkMenuItem *menuitem, gpointer user_data) { GUINode* my_node = reinterpret_cast(user_data); GUINetwork* my_net = dynamic_cast(my_node->getNetwork()); //delete all selected nodes... if (my_net) { if (my_net->isNodeSelected(my_node)) { my_net->clearSelectedNodes(); } else { delete my_node; } } else { delete my_node; } } void GUINode::propertiesShow() { GUINodeParameters *my_params = dynamic_cast(parameters); if (my_params) { my_params->show(); } } void GUINode::help() { string fullPath = UIDocument::findExternal(type + ".cc", "VFLOW_SOURCE", false); if (fullPath == "") fullPath = UIDocument::findExternal(type + ".cpp", "VFLOW_SOURCE", false); //FIXME: gnome 2 /*if (fullPath == "") cerr << "Node help not found\n"; else gnome_help_goto(NULL, const_cast(fullPath.c_str())); */ } void GUINode::createPopup() { popupMenu = gtk_menu_new(); GtkWidget *label; /* label = gtk_menu_item_new_with_label("Add input"); gtk_menu_append(GTK_MENU(popupMenu),label); gtk_widget_show(label); gtk_widget_ref (label); gtk_object_set_data_full (GTK_OBJECT (popupMenu), "label", label, (GtkDestroyNotify) gtk_widget_unref); gtk_signal_connect(GTK_OBJECT(label), "activate", (GtkSignalFunc) node_add_input, this); label = gtk_menu_item_new_with_label("Add output"); gtk_menu_append(GTK_MENU(popupMenu),label); gtk_widget_show(label); gtk_widget_ref (label); gtk_object_set_data_full (GTK_OBJECT (popupMenu), "label", label, (GtkDestroyNotify) gtk_widget_unref); gtk_signal_connect(GTK_OBJECT(label), "activate", (GtkSignalFunc) node_add_output, this); */ label = gtk_menu_item_new_with_label("Properties"); gtk_menu_append(GTK_MENU(popupMenu),label); gtk_widget_show(label); gtk_widget_ref (label); gtk_object_set_data_full (GTK_OBJECT (popupMenu), "label", label, (GtkDestroyNotify) gtk_widget_unref); gtk_signal_connect(GTK_OBJECT(label), "activate", (GtkSignalFunc) node_prop, this); label = gtk_menu_item_new_with_label("Help"); gtk_menu_append(GTK_MENU(popupMenu),label); gtk_widget_show(label); gtk_widget_ref (label); gtk_object_set_data_full (GTK_OBJECT (popupMenu), "label", label, (GtkDestroyNotify) gtk_widget_unref); gtk_signal_connect(GTK_OBJECT(label), "activate", (GtkSignalFunc) node_help, this); GtkWidget *separ = gtk_menu_item_new(); gtk_menu_append(GTK_MENU(popupMenu),separ); gtk_widget_show(separ); gtk_widget_ref (separ); gtk_object_set_data_full (GTK_OBJECT (popupMenu), "label", separ, (GtkDestroyNotify) gtk_widget_unref); label = gtk_menu_item_new_with_label("Delete"); gtk_menu_append(GTK_MENU(popupMenu),label); gtk_widget_show(label); gtk_widget_ref (label); gtk_object_set_data_full (GTK_OBJECT (popupMenu), "label", label, (GtkDestroyNotify) gtk_widget_unref); gtk_signal_connect(GTK_OBJECT(label), "activate", (GtkSignalFunc) node_delete, this); } void GUINode::doGrab() { GdkCursor *fleur; GnomeCanvasItem *item=GNOME_CANVAS_ITEM(group); xtmp = x; ytmp = y; fleur = gdk_cursor_new(GDK_FLEUR); gnome_canvas_item_grab(item, GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK | GDK_BUTTON_PRESS_MASK, //GDK_ALL_EVENTS_MASK, fleur, 0); gdk_cursor_destroy(fleur); dragging = TRUE; grab=true; } gint GUINode::event(GdkEvent *event) { // static double x, y; double new_x, new_y; GdkCursor *fleur; //static int dragging; double item_x, item_y; GnomeCanvasItem *item=GNOME_CANVAS_ITEM(group); item_x = event->button.x; item_y = event->button.y; gnome_canvas_item_w2i(item->parent, &item_x, &item_y); //cerr << "+"; NodeInfo *my_info = getNetwork()->getDocument()->getRepository().findNode(getType()); switch (event->type) { case GDK_BUTTON_PRESS: //cerr<<"GUINode button event"<button.button) { case 1: if (event->button.state & GDK_SHIFT_MASK) { //dynamic_cast (parameters)->show(); //delete this; //cloning... //creating new node GUINetwork *my_net = dynamic_cast(net); GUINode *my_node = dynamic_cast(my_net->addNode(getType(),item_x + 10,item_y + 10)); //copying parameters UINodeParameters *params_source = getParameters() ; //copying inputs (for resizable nodes) std::vector all_inputs = getInputs(); for (int i = 0; i < all_inputs.size(); i++) { string input_name = all_inputs[i]->getName(); string input_type = all_inputs[i]->getType(); if (my_node->getInputNamed(input_name) == NULL) { //add this input my_node->addTerminal(string(input_name), UINetTerminal::INPUT); } } //copying outputs (for resizable nodes) std::vector all_outputs = getOutputs(); for (int i = 0; i < all_outputs.size(); i++) { string output_name = all_outputs[i]->getName(); string output_type = all_outputs[i]->getType(); if (my_node->getOutputNamed(output_name) == NULL) { //add this output my_node->addTerminal(string(output_name), UINetTerminal::OUTPUT); } } //FIXME : PROBABLE LEAK. UINodeParameters *params_destination = new GUINodeParameters(my_node,getType()); params_destination->copyParameterText(params_source); my_node->setNodeParameters(params_destination); return true; } else if (event->button.state & GDK_CONTROL_MASK) { } else { if (dragging && grab) { //cerr << "stop drag\n"; gnome_canvas_item_ungrab(item, event->button.time); dragging = FALSE; grab=false; dynamic_cast(net)->updateScroll(); } else { //cerr << "start drag\n"; xtmp = item_x; ytmp = item_y; fleur = gdk_cursor_new(GDK_FLEUR); gnome_canvas_item_grab(item, GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK | GDK_FOCUS_CHANGE_MASK | GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK | GDK_BUTTON_PRESS_MASK, //GDK_ALL_EVENTS_MASK, fleur, event->button.time); //if not already selected if (!dynamic_cast(net)->isNodeSelected(this)) { //selecting node select(); //unselect other nodes dynamic_cast(net)->emptySelectedNodes(); //adding this one to the selected list dynamic_cast(net)->addSelectedNode(this); } gdk_cursor_destroy(fleur); dragging = TRUE; } } return TRUE; break; case 2: //dynamic_cast (net)->popTooltip(this); vflowGUI::instance()->display_treeview_nodetype(getType()); return TRUE; break; case 3: gnome_popup_menu_do_popup_modal (popupMenu,NULL,NULL,&(event->button),NULL, GTK_WIDGET(dynamic_cast(net)->getCanvas())); return TRUE; break; default: break; } break; case GDK_MOTION_NOTIFY: if (my_info) { vflowGUI::instance()->display_statusbar_text(getName() + getDescription() + string(" : ") + my_info->description); } else { vflowGUI::instance()->display_statusbar_text(getName()); } /*if (event->button.state & GDK_SHIFT_MASK) { dynamic_cast(net)->popTooltip(this); } else { dynamic_cast(net)->popTooltip(NULL); }*/ if (dragging && (grab || (event->motion.state & GDK_BUTTON1_MASK))) { new_x = item_x; new_y = item_y; move(new_x - xtmp, new_y - ytmp); //gnome_canvas_item_move(item, new_x - xtmp, new_y - ytmp); xtmp = new_x; ytmp = new_y; net->setModified(); dynamic_cast(net)->auto_scroll(item_x,item_y); } return TRUE; break; case GDK_ENTER_NOTIFY: dynamic_cast(net)->popTooltip(this); break; case GDK_LEAVE_NOTIFY: dynamic_cast(net)->popTooltip(NULL); break; case GDK_BUTTON_RELEASE: if (!grab) { //printf ("button release on node\n"); gnome_canvas_item_ungrab(item, event->button.time); dragging = FALSE; dynamic_cast (net)->updateScroll(); } break; case GDK_2BUTTON_PRESS: //cerr << "double-click\n"; //dynamic_cast (parameters)->show(); propertiesShow(); break; default: break; } return FALSE; } void GUINode::move(double dx, double dy) { GUINetwork *my_net = dynamic_cast(net); if (my_net->isNodeSelected(this)) { my_net->moveSelectedNodes(dx,dy); } else { int i; setPos(x + dx, y + dy); gnome_canvas_item_move(GNOME_CANVAS_ITEM(group), dx, dy); for (i=0;i(inputs[i])->move(dx, dy); for (i=0;i(outputs[i])->move(dx, dy); } } void GUINode::selectedMove(double dx,double dy) { int i; setPos(x + dx, y + dy); gnome_canvas_item_move(GNOME_CANVAS_ITEM(group), dx, dy); for (i=0;i(inputs[i])->move(dx, dy); for (i=0;i(outputs[i])->move(dx, dy); } UILink *GUINode::newLink (UITerminal *_from, UITerminal *_to) { return new GUILink (_from, _to); } UINetTerminal *GUINode::newNetTerminal (UITerminal *_terminal, UINetTerminal::NetTermType _type, const string &_name, const string &_objType, const string &_description) { return new GUINetTerminal (_terminal, _type, _name, _objType, _description); } void GUINode::addTerminal(const string &_name, UINetTerminal::NetTermType _type, const string &_objType, const string &_description) { double x1=0,y1=0,x2=0,y2=0; gnome_canvas_item_get_bounds(nodeRect, &x1,&y1,&x2,&y2); ItemInfo info; info.name = _name; info.type = _objType; info.description = _description; switch (_type) { case UINetTerminal::INPUT : inputs.insert(inputs.end(), new GUITerminal (&info, this, true, x1, y1)); break; case UINetTerminal::OUTPUT: outputs.insert(outputs.end(), new GUITerminal (&info, this, false, x2,y2 )); break; default: break; } redraw(); } void GUINode::initialize_widgets() { double x1,y1,x2,y2; GnomeCanvasItem *item1,*item2; //getting the group GnomeCanvasGroup* netGroup = dynamic_cast (net)->getGroup(); //creating the group group = GNOME_CANVAS_GROUP (gnome_canvas_item_new (netGroup, gnome_canvas_group_get_type(), "x", x, "y", y, NULL)); //creating the node name nodeText = gnome_canvas_item_new(group, gnome_canvas_text_get_type(), "x", 0.0, "y", 0.0, "text", type.c_str(), "anchor", GTK_ANCHOR_CENTER, "fill_color", "black", "font", "sans 10", NULL); //getting the node bounds gnome_canvas_item_get_bounds(nodeText, &x1,&y1, &x2, &y2); gnome_canvas_item_raise_to_top(nodeText); vector inputname = net->getDocument()->getNetInputs(type); vector outputname = net->getDocument()->getNetOutputs(type); //creating input items for (int i=0;i 1 || FlowPref::getBool("VFLOW", "ShowAllInOut")) { for (int i = 0; i < inSize; i++) { max_inputs = max(max_inputs,dynamic_cast(inputs[i])->getWidth() + 10.0); } } //finding max size for text + output terminal if (outSize > 1 || FlowPref::getBool("VFLOW", "ShowAllInOut")) { for (int i = 0; i < outSize; i++) { max_outputs = max(max_outputs,dynamic_cast(outputs[i])->getWidth() + 10.0); } } //let's position the inputs for (int i = 0; i < inSize; i++) { if (inSize > 1 || FlowPref::getBool("VFLOW", "ShowAllInOut")) { dynamic_cast(inputs[i])->showName(); } else { dynamic_cast(inputs[i])->hideName(); } //position text & terminal dynamic_cast(inputs[i])->setAbsPos(tx1 - max_inputs, start_y1 + 15 * (i)); //reposition netTerminal if (inputs[i]->getNetTerminal()) { //TODO reposition net terminal //DL 1 Feb 2002 dynamic_cast(inputs[i]->getNetTerminal())->setAbsPos(tx1 - max_outputs - 10, start_y1 + 15 * (i)); } }//inputs //let's find the maximum width of the output for (int i = 0; i < outSize; i++) { if (outSize > 1 || FlowPref::getBool("VFLOW", "ShowAllInOut")) { dynamic_cast(outputs[i])->showName(); } else { dynamic_cast(outputs[i])->hideName(); } //position text & terminal dynamic_cast(outputs[i])->setAbsPos(tx2 + max_outputs, start_y2 + 15 * (i)); //reposition netTerminal if (outputs[i]->getNetTerminal()) { //TODO reposition net terminal //DL 1 Feb 2002 dynamic_cast(outputs[i]->getNetTerminal())->setAbsPos(tx2 + max_outputs + 10, start_y2 + 15 * (i)); } }//outputs rx1 -= max_inputs; rx2 += max_outputs; //dont forget text size ry1 = min(start_y1,start_y2) - 10; ry2 = min(start_y1,start_y2) + 15.0 * max(0,max(inSize -1,outSize -1)) + 10; //updating rectangle gnome_canvas_item_set(nodeRect, "x1",rx1, "y1",ry1, "x2",rx2, "y2",ry2, NULL); //updating node label gnome_canvas_item_set(nodeLabel, "x",(rx1 + rx2) / 2.0, "y",ry2 + 10.0, NULL); } void GUINode::notifyError(const string &message) { guint32 col = FlowPref::getColor("VFLOW", "ErrorColor"); gnome_canvas_item_set (nodeRect, "fill_color_rgba", col, NULL); //cerr << "color" << endl; //dynamic_cast (getNetwork())->updateScroll(); } void GUINode::select() { guint32 col = FlowPref::getColor("VFLOW", "SelectedColor"); gnome_canvas_item_set (nodeRect, "fill_color_rgba", col, NULL); } void GUINode::unselect() { guint32 col = FlowPref::getColor("VFLOW", "RegularColor"); gnome_canvas_item_set (nodeRect, "fill_color_rgba", col, NULL); } void GUINode::getBounds(double &x1, double &y1, double &x2, double &y2) { //getting bounds of the group gnome_canvas_item_get_bounds (GNOME_CANVAS_ITEM(group), &x1, &y1, &x2, &y2); } void GUINode::rename(const string &newName) { UINode::rename(newName); //change the type text gnome_canvas_item_set(nodeText,"text",type.c_str(),NULL); redraw(); } UINodeParameters *GUINode::newNodeParameters (UINode *_node, string type) { return new GUINodeParameters (_node, type); } }//namespace FD