import java.awt.*; import java.awt.event.*; import java.lang.Math; import java.util.*; import javax.swing.*; import com.genlogic.*; ////////////////////////////////////////////////////////////////////////// // A diagramming editor: example of using Extended API. // // This demo uses Glg as a bean and may be used in a browser or // stand-alone. // // The CustomHandler class provides callbacks for interfacing with // application-specific functionality. ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// public class GlgDiagram extends GlgJBean { static final long serialVersionUID = 0; // Constants // Selection sensitivity in pixels static final int SELECTION_RESOLUTION = 5; static final int POINT_SELECTION_RESOLUTION = 2; // Number of palette buttons to skip: the first button with the // "select" icon is already in the palette. static final int PALETTE_START_INDEX = 1; // Default scale factor for icon buttons. static final double DEFAULT_ICON_SCALE = 10.; // Scale factor when placed in the drawing static final double IconScale = 1.; // Editing Modes static final int SELECT_OBJECT = 0; static final int ADD_NODE = 4; static final int ADD_LINK1 = 5; static final int ADD_LINK2 = 6; static final int DRAGGING = 7; // Object types static final int NO_OBJ = 0; static final int NODE = 1; static final int LINK = 2; boolean StandAlone; GlgObject Viewport; GlgObject MainArea; GlgObject SelectedObject = null; GlgObject SelectedMarker = null; boolean StickyCreateMode = false; boolean AllowUnconnectedLinks = true; boolean PointFeedbackShown = false; int SelectedObjectType; int NodeType; int LinkType; GlgObject DragLink; int EdgeType; GlgObject Point1; GlgObject StoredColor; GlgObject CutBuffer; int CutBufferType; int Mode; int NumLinkPoints; boolean MiddlePointAdded = false; String LastButton; GlgObject Handler; GlgDiagramData CurrentDiagram = new GlgDiagramData(); GlgDiagramData SavedDiagram; GlgObject NodeIconArray; GlgObject NodeObjectArray; GlgObject LinkIconArray; GlgObject LinkObjectArray; GlgObject PaletteTemplate; GlgObject ButtonTemplate; int NumRows; int NumColumns; GlgPoint cursor_pos = new GlgPoint(); GlgPoint world_coord = new GlgPoint(); GlgPoint screen_coord = new GlgPoint(); GlgPoint start_point = new GlgPoint(); GlgPoint end_point = new GlgPoint(); GlgCube select_rect = new GlgCube(); GlgObject last_color; // Stores color during selection. ////////////////////////////////////////////////////////////////////////// // Utility class used to return several values. ////////////////////////////////////////////////////////////////////////// class ObjectInfo { GlgObject object; int type; // Constructors ObjectInfo() {} ObjectInfo( GlgObject object_p, int type_p ) { object = object_p; type = type_p; } } ////////////////////////////////////////////////////////////////////////// public GlgDiagram() { super(); SetDResource( "$config/GlgSwingUsage", 1. ); SelectedObjectType = NO_OBJ; CutBufferType = NO_OBJ; Mode = SELECT_OBJECT; LastButton = null; // The bean is a default listener for bean events except the trace // events (which are disabled by default), but add all listeners // explicitely as an example. AddListener( GlgObject.H_CB, this ); AddListener( GlgObject.V_CB, this ); AddListener( GlgObject.READY_CB, this ); AddListener( GlgObject.INPUT_CB, this ); AddListener( GlgObject.TRACE_CB, this ); } ////////////////////////////////////////////////////////////////////////// // For use as a stand-alone java demo ////////////////////////////////////////////////////////////////////////// public static void main( final String arg[] ) { SwingUtilities. invokeLater( new Runnable(){ public void run() { Main( arg ); } } ); } ////////////////////////////////////////////////////////////////////////// public static void Main( final String arg[] ) { class DemoQuit extends WindowAdapter { public void windowClosing( WindowEvent e ) { System.exit( 0 ); } } JFrame frame = new JFrame(); frame.setResizable( true ); frame.setSize( 900, 700 ); frame.setLocation( 20, 20 ); GlgDiagram diagram = new GlgDiagram(); diagram.StandAlone = true; // Loading the drawing triggers the H, V and Ready callbacks. // When used as an applet, the DrawingName parameter is set in HTML. // diagram.SetDrawingName( "diagram.g" ); frame.getContentPane().add( diagram ); frame.addWindowListener( new DemoQuit() ); frame.setVisible( true ); } ////////////////////////////////////////////////////////////////////////// // Invoked after the drawing has been loaded but before it's set up. ////////////////////////////////////////////////////////////////////////// public void HCallback( GlgObject viewport ) { // Fill out the palette and change the dialog type before the // hierarchy setup Viewport = GetViewport(); MainArea = Viewport.GetResourceObject( "MainArea" ); if( MainArea == null ) { PrintToJavaConsole( "Can't find MainArea viewport.\n" ); return; } PaletteTemplate = Viewport.GetResourceObject( "PaletteTemplate" ); if( PaletteTemplate == null ) { PrintToJavaConsole( "Can't find PaletteTemplate viewport.\n" ); return; } Viewport.DeleteObject( PaletteTemplate ); // Create groups to hold nodes and links. NodeIconArray = new GlgDynArray( GlgObject.GLG_OBJECT, 0, 0 ); NodeObjectArray = new GlgDynArray( GlgObject.GLG_OBJECT, 0, 0 ); LinkIconArray = new GlgDynArray( GlgObject.GLG_OBJECT, 0, 0 ); LinkObjectArray = new GlgDynArray( GlgObject.GLG_OBJECT, 0, 0 ); // Scan palette template and extract icon and link objects, adding them // to the buttons in the object palette. GetPaletteIcons( PaletteTemplate, "Node", NodeIconArray, NodeObjectArray ); GetPaletteIcons( PaletteTemplate, "Link", LinkIconArray, LinkObjectArray ); FillObjectPalette( "ObjectPalette", "IconButton", PALETTE_START_INDEX ); } ////////////////////////////////////////////////////////////////////////// // Invoked after the drawing has been loaded and set up, but before it's // displayed. ////////////////////////////////////////////////////////////////////////// public void VCallback( GlgObject viewport ) { // Do some initialization here before displaying the drawing. SetPrompt( "" ); // Create a color object to store original node color during node // selection. StoredColor = Viewport.GetResourceObject( "FillColor" ).CopyObject(); // Make exit button visible for stand-alone. if( StandAlone ) Viewport.SetDResource( "Exit/Visibility", 1. ); else Viewport.SetDResource( "Exit/Visibility", 0. ); // Set grid color (configuration parameter) to grey. Viewport.SetGResource( "$config/GlgGridPolygon/EdgeColor", 0.632441, 0.632441, 0.632441 ); // Change the shell type of the Properties dialog to make it a separate // top-level window, and make it invisible on start-up. // You can replace the dialog with any custom Java-based dialog. Viewport.SetDResource( "Dialog/ShellType", (double) GlgObject.DIALOG_SHELL ); Viewport.SetDResource( "Dialog/Visibility", 0. ); // Set the Properties dialog's title. Viewport.SetSResource( "Dialog/ScreenName", "Object Properties" ); // Create a separate group to hold objects. GlgObject group = new GlgDynArray( GlgObject.GLG_OBJECT, 0, 0 ); group.SetSResource( "Name", "ObjectGroup" ); MainArea.AddObjectToBottom( group ); Mode = SELECT_OBJECT; SetRadioBox( "IconButton0" ); // Highlight Select button SetCreateMode(); // Query initial create mode from the drawing. CurrentDiagram = new GlgDiagramData(); // Position node icons inside the palette buttons. SetupObjectPalette( "IconButton", PALETTE_START_INDEX ); } ////////////////////////////////////////////////////////////////////////// // Invoked after the drawing has been drawn for the first time. ////////////////////////////////////////////////////////////////////////// public void ReadyCallback( GlgObject viewport ) { // May be used to start data updates, not used here. } ////////////////////////////////////////////////////////////////////////// // Sets create mode based on the state of the CreateMode button. ////////////////////////////////////////////////////////////////////////// void SetCreateMode() { int create_mode = (int) GetDResource( "CreateMode/OnState" ); StickyCreateMode = ( create_mode != 0 ); } //////////////////////////////////////////////////////////////////////// // The trace callback receives all low-level events and is used for // handling mouse interaction, such as creating and dragging nodes // and links. // // The TraceCB requires handling native events as the price of the extended // functionality it provides. However, the native code is limited to just // a few code lines to extract the platform-specific event information. //////////////////////////////////////////////////////////////////////// public void TraceCallback( GlgObject viewport, GlgTraceData trace_info ) { int event_type; // Use the MainArea's events only. if( !IsReady() || trace_info.viewport != MainArea ) return; event_type = trace_info.event.getID(); switch( event_type ) { case MouseEvent.MOUSE_PRESSED: case MouseEvent.MOUSE_MOVED: case MouseEvent.MOUSE_DRAGGED: case MouseEvent.MOUSE_RELEASED: if( GetButton( trace_info.event ) != 1 ) return; // Use the left button clicks only. cursor_pos.x = (double) ((MouseEvent)trace_info.event).getX(); cursor_pos.y = (double) ((MouseEvent)trace_info.event).getY(); cursor_pos.z = 0.; break; default: return; } if( MainArea.GetDResource( "ZoomToMode" ).intValue() != 0 ) return; // Don't handle mouse selection in ZoomTo mode. switch( Mode ) { default: Bell(); ResetModes(); Update(); return; case ADD_NODE: AddNodeHandler( event_type, cursor_pos ); return; case ADD_LINK1: case ADD_LINK2: AddLinkHandler( event_type, cursor_pos, viewport, trace_info ); return; case DRAGGING: DraggingHandler( event_type, cursor_pos ); return; case SELECT_OBJECT: ObjectHandler( event_type, cursor_pos, viewport, trace_info ); return; } } //////////////////////////////////////////////////////////////////////// public void AddNodeHandler( int event_type, GlgPoint cursor_pos ) { if( event_type != MouseEvent.MOUSE_PRESSED ) return; // Use screen coords of the cursor to add graphics GlgObject new_node = AddNodeAt( NodeType, null, cursor_pos, GlgObject.SCREEN_COORD ); CustomHandler.AddObjectCB( this, new_node, GetData( new_node ), true ); SelectGlgObject( new_node, NODE ); if( !StickyCreateMode ) ResetModes(); Update(); } //////////////////////////////////////////////////////////////////////// public void AddLinkHandler( int event_type, GlgPoint cursor_pos, GlgObject viewport, GlgTraceData trace_info ) { GlgObject point, sel_object = null; GlgLinkData link_data; int num_selected; if( event_type != MouseEvent.MOUSE_PRESSED && event_type != MouseEvent.MOUSE_MOVED ) return; // Drag the link if( event_type == MouseEvent.MOUSE_MOVED && Mode == ADD_LINK2 ) { link_data = (GlgLinkData) GetData( DragLink ); // First time: set link direction depending of the // direction of the first mouse move, then make the link visible. if( link_data.first_move ) { SetEdgeDirection( DragLink, start_point, cursor_pos ); DragLink.SetDResource( "Visibility", 1. ); link_data.first_move = false; } SetLastPoint( DragLink, cursor_pos, false ); if( !MiddlePointAdded ) SetArcMiddlePoint( DragLink ); Update(); } GlgObject selection = GetObjectsAtCursor( /** top viewport **/ viewport, /** event viewport **/ trace_info.viewport, cursor_pos ); if( selection != null && ( num_selected = selection.GetSize() ) != 0 ) { // Some objects were selected, process the selection to find the // point to connect to. point = null; for( int i=0; i < num_selected; ++i ) { sel_object = (GlgObject) selection.GetElement( i ); // Find if the object itself is a link or a node, // of if it's a part of a node. If it's a part of a node, // get the node object ID. // ObjectInfo selection_info = GetSelectedObject( sel_object ); sel_object = selection_info.object; int selection_type = selection_info.type; if( selection_type == NODE ) { int type = sel_object.GetDResource( "Type" ).intValue(); if( type == GlgObject.REFERENCE ) { // Use ref's point as a connector. point = sel_object.GetResourceObject( "Point" ); } else { // Node has multiple connectors. Get connection point point = GetSelectedPoint( sel_object, cursor_pos, "CP" ); } if( point != null ) break; // Found a point to connect to: stop search and use it. } // No point to connect to: continue searching all selected objects. } if( point != null ) // Use point if found. { switch( event_type ) { // Show feedback at the connector's position. case MouseEvent.MOUSE_MOVED: // Get screen coords of the connector point, not the cursor // position: may be a few pixels off. GlgPoint screen_point = point.GetGResource( "XfValue" ); MainArea.ScreenToWorld( true, screen_point, world_coord ); // Position the feedback marker over the connector SelectedMarker.SetGResource( "Point", world_coord ); if( !PointFeedbackShown ) { MainArea.AddObjectToBottom( SelectedMarker ); PointFeedbackShown = true; } Update(); break; case MouseEvent.MOUSE_PRESSED: // Connect switch( Mode ) { case ADD_LINK1: Point1 = point; DragLink = AddLink( LinkType, null ); NumLinkPoints = 1; // First point ConstrainLinkPoint( DragLink, Point1, false ); AttachFramePoints( DragLink ); // Wire up the start node link_data = (GlgLinkData) GetData( DragLink ); link_data.setStartNode( (GlgNodeData)GetData( sel_object ) ); // Store cursor position for setting direction based on the // first mouse move. start_point.CopyFrom( cursor_pos ); link_data.first_move = true; DragLink.SetDResource( "Visibility", 0. ); Mode = ADD_LINK2; SetPrompt( "Select the second node." ); Update(); break; case ADD_LINK2: if( point == Point1 ) { SetError( "The two nodes are the same, " + "chose a different second node." ); break; } ++NumLinkPoints; // Last point ConstrainLinkPoint( DragLink, point, true ); AttachFramePoints( DragLink ); if( !MiddlePointAdded ) SetArcMiddlePoint( DragLink ); // Wire up the end node link_data = (GlgLinkData) GetData( DragLink ); link_data.setEndNode( (GlgNodeData) GetData( sel_object ) ); FinalizeLink( DragLink ); DragLink = null; if( StickyCreateMode ) { // Start over to create more links Mode = ADD_LINK1; SetPrompt( "Select the first node." ); MiddlePointAdded = false; } else ResetModes(); Update(); break; } } /* switch( event_type ) */ return; // We are done with the point. } /* if( point != null ) */ } // No point or no selection: handle point feedback and link middle // points. if( PointFeedbackShown ) { MainArea.DeleteObject( SelectedMarker ); PointFeedbackShown = false; Update(); } if( event_type == MouseEvent.MOUSE_PRESSED ) // Add midlle link point { if( Mode == ADD_LINK1 ) { SetError( "Invalid connection point!" ); return; // No first point yet } ++NumLinkPoints; // Add middle link point. AddLinkPoints( DragLink, 1 ); MiddlePointAdded = true; SetLastPoint( DragLink, cursor_pos, EdgeType == GlgObject.ARC ); AttachFramePoints( DragLink ); if( EdgeType == GlgObject.ARC ) { // Offset the last point after setting the middle one. cursor_pos.x += 10; cursor_pos.y += 10; SetLastPoint( DragLink, cursor_pos, false ); } Update(); } } //////////////////////////////////////////////////////////////////////// void FinalizeLink( GlgObject link ) { GlgObject arrow_type = link.GetResourceObject( "ArrowType" ); if( arrow_type != null ) arrow_type.SetDResource( null, (double) GlgObject.MIDDLE_FILL_ARROW ); GlgLinkData link_data = (GlgLinkData) GetData( link ); // Store points StorePointData( link_data, link ); // Add link data to the link list Vector link_list = CurrentDiagram.getLinkList(); link_list.addElement( link_data ); // After storing color: changes color to select. SelectGlgObject( link, LINK ); CustomHandler.AddObjectCB( this, link, GetData( link ), false ); } //////////////////////////////////////////////////////////////////////// // Stores point coordinates in the link data structure as a vector. //////////////////////////////////////////////////////////////////////// void StorePointData( GlgLinkData link_data, GlgObject link ) { ObjectInfo link_info = GetCPContainer( link ); GlgObject point_container = link_info.object; int num_points = point_container.GetSize(); // Always create a new vector and discard the old one for simplicity // (not much to gain any way). link_data.point_array = new Vector( num_points ); for( int i=0; i 2 ) AddLinkPoints( new_link, num_points - 2 ); AddCustomData( new_link, link_data ); return new_link; } ///////////////////////////////////////////////////////////////////////// // Connects the first or last point of the link. ///////////////////////////////////////////////////////////////////////// void ConstrainLinkPoint( GlgObject link, GlgObject point, boolean last_point ) { ObjectInfo link_info = GetCPContainer( link ); GlgObject point_container = link_info.object; GlgObject link_point = (GlgObject) point_container.GetElement( ( last_point ? point_container.GetSize() - 1 : 0 ) ); GlgObject suspend_info = link.SuspendObject(); link_point.ConstrainObject( point ); link.ReleaseObject( suspend_info ); // Store the point name for save/load String point_name = point.GetSResource( "Name" ); if( point_name == null || point_name.length() == 0 ) point_name = "Point"; GlgLinkData link_data = (GlgLinkData) GetData( link ); if( last_point ) link_data.end_point_name = point_name; else link_data.start_point_name = point_name; } ///////////////////////////////////////////////////////////////////////// // Positions the arc's middle point if it's not explicitly defined. ///////////////////////////////////////////////////////////////////////// void SetArcMiddlePoint( GlgObject link ) { ObjectInfo link_info = GetCPContainer( link ); GlgObject point_container = link_info.object; int edge_type = link_info.type; if( edge_type != GlgObject.ARC ) return; // Offset the arc's middle point if wasn't set. GlgObject start_point = (GlgObject) point_container.GetElement( 0 ); GlgObject middle_point = (GlgObject) point_container.GetElement( 1 ); GlgObject end_point = (GlgObject) point_container.GetElement( 2 ); GlgPoint pt1 = start_point.GetGResource( null ); GlgPoint pt2 = end_point.GetGResource( null ); // Offset the middle point. middle_point.SetGResource( null, ( pt1.x + pt2.x ) / 2. + ( pt1.y - pt2.y != 0. ? 50. : 0. ), ( pt1.y + pt2.y ) / 2. + ( pt1.y - pt2.y != 0. ? 0. : 50. ), ( pt1.z + pt2.z ) / 2. ); } ///////////////////////////////////////////////////////////////////////// // Handles links with labels: constrains frame's points to the link's // points. ///////////////////////////////////////////////////////////////////////// void AttachFramePoints( GlgObject link ) { GlgObject frame, link_point_container, frame_point_container, link_start_point, link_end_point, frame_start_point, frame_end_point, suspend_info; frame = link.GetResourceObject( "Frame" ); if( frame == null ) // Link without label and frame return; ObjectInfo link_info = GetCPContainer( link ); link_point_container = link_info.object; // Always use the first segment of the link to attach the frame. link_start_point = (GlgObject) link_point_container.GetElement( 0 ); link_end_point = (GlgObject) link_point_container.GetElement( 1 ); frame_point_container = frame.GetResourceObject( "CPArray" ); int size = frame_point_container.GetSize(); frame_start_point =(GlgObject) frame_point_container.GetElement( 0 ); frame_end_point = (GlgObject) frame_point_container.GetElement( size - 1 ); suspend_info = link.SuspendObject(); frame_start_point.ConstrainObject( link_start_point ); frame_end_point.ConstrainObject( link_end_point ); link.ReleaseObject( suspend_info ); } ///////////////////////////////////////////////////////////////////////// // Disconnects the first or last point of the link. Returns the object // the link is connected to. ///////////////////////////////////////////////////////////////////////// GlgObject UnConstrainLinkPoint( GlgObject link, boolean last_point ) { ObjectInfo link_info = GetCPContainer( link ); GlgObject point_container = link_info.object; GlgObject link_point = (GlgObject) point_container.GetElement( ( last_point ? point_container.GetSize() - 1 : 0 ) ); GlgObject attachment_point = link_point.GetResourceObject( "Data" ); GlgObject suspend_info = link.SuspendObject(); link_point.UnconstrainObject(); link.ReleaseObject( suspend_info ); return attachment_point; } ///////////////////////////////////////////////////////////////////////// // Detaches the first and last points of the frame. ///////////////////////////////////////////////////////////////////////// void DetachFramePoints( GlgObject link ) { GlgObject frame, frame_point_container, frame_start_point, frame_end_point, suspend_info; frame = link.GetResourceObject( "Frame" ); if( frame == null ) // Link without label and frame return; frame_point_container = frame.GetResourceObject( "CPArray" ); int size = frame_point_container.GetSize(); frame_start_point = (GlgObject) frame_point_container.GetElement( 0 ); frame_end_point = (GlgObject) frame_point_container.GetElement( size - 1 ); suspend_info = link.SuspendObject(); frame_start_point.UnconstrainObject(); frame_end_point.UnconstrainObject(); link.ReleaseObject( suspend_info ); } ///////////////////////////////////////////////////////////////////////// // Set last point of the link (dragging). ///////////////////////////////////////////////////////////////////////// void SetLastPoint( GlgObject link, GlgPoint cursor_pos, boolean arc_middle_point ) { GlgObject point; ObjectInfo link_info = GetCPContainer( link ); GlgObject point_container = link_info.object; if( arc_middle_point ) // Setting the middle point of an arc. point = (GlgObject) point_container.GetElement( 1 ); else // Setting the last point. point = (GlgObject) point_container.GetElement( point_container.GetSize() - 1 ); MainArea.ScreenToWorld( true, cursor_pos, world_coord ); point.SetGResource( null, world_coord ); } ///////////////////////////////////////////////////////////////////////// void AddLinkPoints( GlgObject link, int num_points ) { ObjectInfo link_info = GetCPContainer( link ); if( link_info.type == GlgObject.ARC ) return; // Arc connectors have fixed number of points: don't add. GlgObject point_container = link_info.object; GlgObject point = (GlgObject) point_container.GetElement( 0 ); GlgObject suspend_info = link.SuspendObject(); for( int i=0; i Math.abs( start_pos.y - end_pos.y ) ) direction = GlgObject.HORIZONTAL; else direction = GlgObject.VERTICAL; link.SetDResource( "EdgeDirection", (double) direction ); GlgLinkData link_data = (GlgLinkData) GetData( link ); link_data.link_direction = direction; } //////////////////////////////////////////////////////////////////////// GlgObject AddLink( int link_type, GlgLinkData link_data ) { GlgObject link; if( link_data == null ) // Creating a new link interactively { link_data = new GlgLinkData(); link_data.link_type = link_type; link = CreateLink( link_data ); // Store color link_data.link_color = new GlgDiagramPoint( link.GetGResource( "EdgeColor" ) ); // Don't add link data to the link list or store points: // will be done when finished creating the link. } else // Creating a link from data on load. { link = CreateLink( link_data ); // Set color link.SetGResource( "EdgeColor", link_data.link_color ); // Enable arrow type if defined GlgObject arrow_type = link.GetResourceObject( "ArrowType" ); if( arrow_type != null ) arrow_type.SetDResource( null, (double) GlgObject.MIDDLE_FILL_ARROW ); // Restore connector direction if recta-linear GlgObject direction = link.GetResourceObject( "EdgeDirection" ); if( direction != null ) direction.SetDResource( null, (double) link_data.link_direction ); // Constrain end points to start and end nodes GlgNodeData start_node = link_data.getStartNode(); if( start_node != null ) { GlgObject node1 = start_node.graphics; GlgObject point1 = node1.GetResourceObject( link_data.start_point_name ); ConstrainLinkPoint( link, point1, false ); // First point } GlgNodeData end_node = link_data.getEndNode(); if( end_node != null ) { GlgObject node2 = end_node.graphics; GlgObject point2 = node2.GetResourceObject( link_data.end_point_name ); ConstrainLinkPoint( link, point2, true ); // Last point } AttachFramePoints( link ); RestorePointData( link_data, link ); } // Display the label if it's a link with a label. if( link.HasResourceObject( "Label" ) ) link.SetSResource( "Label/String", link_data.object_label ); link_data.graphics = link; // Pointer from data struct to graphics // Add to the top of the draw list to be behind other objects. GlgObject group = MainArea.GetResourceObject( "ObjectGroup" ); group.AddObjectToTop( link ); return link; } //////////////////////////////////////////////////////////////////////// // Set the object size and position. //////////////////////////////////////////////////////////////////////// void PlaceObject( GlgObject node, GlgPoint pos, int coord_type, GlgPoint world_coord ) { int type; // World coordinates of the node are returned to be stored in the node's // data structure. if( coord_type == GlgObject.SCREEN_COORD ) MainArea.ScreenToWorld( true, pos, world_coord ); else world_coord.CopyFrom( pos ); type = node.GetDResource( "Type" ).intValue(); if( type == GlgObject.REFERENCE ) { // Reference: can use its point to position it. node.SetGResource( "Point", world_coord ); if( IconScale != 1. ) // Change node size if required. // Scale object around the origin, which is now located at pos. node.ScaleObject( coord_type, pos, IconScale, IconScale, 1. ); } else { // Arbitrary object: move its box's center to the cursor position. node.PositionObject( coord_type, GlgObject.HCENTER | GlgObject.VCENTER, pos.x, pos.y, pos.z ); if( IconScale != 1. ) // Change node size if required. // Scale object around the center of it's bounding box. node.ScaleObject( coord_type, null, IconScale, IconScale, 1. ); } } //////////////////////////////////////////////////////////////////////// // Get the link's control points container based on the link type. //////////////////////////////////////////////////////////////////////// ObjectInfo GetCPContainer( GlgObject link ) { ObjectInfo rval; int link_type; link_type = link.GetDResource( "Type" ).intValue(); switch( link_type ) { case GlgObject.POLYGON: rval = new ObjectInfo(); rval.object = link; rval.type = 0; break; case GlgObject.GROUP: // Group containing a polygon with a label return GetCPContainer( link.GetResourceObject( "Link" ) ); case GlgObject.CONNECTOR: rval = new ObjectInfo(); rval.object = link; rval.type = link.GetDResource( "EdgeType" ).intValue(); break; default: SetError( "Invalid link type." ); return null; } return rval; } //////////////////////////////////////////////////////////////////////// // Determines what node or link the object belongs to and returns it. // Also returns type of the object: NODE or LINK. //////////////////////////////////////////////////////////////////////// ObjectInfo GetSelectedObject( GlgObject object ) { while( object != null ) { // Check if the object has IconType. if( object.HasResourceObject( "IconType" ) ) { String type_string = object.GetSResource( "IconType" ); if( type_string.equals( "Link" ) ) return new ObjectInfo( object, LINK ); else if( type_string.equals( "Node" ) ) return new ObjectInfo( object, NODE ); } object = object.GetParent(); } // No node/link parent found - no selection. return new ObjectInfo( null, NO_OBJ ); } //////////////////////////////////////////////////////////////////////// // Returns the first point at the cursor whose name starts with the // name_prefix. //////////////////////////////////////////////////////////////////////// GlgObject GetSelectedPoint( GlgObject sel_object, GlgPoint cursor_pos, String name_prefix ) { int size; GlgObject pt_array = sel_object.CreatePointArray( 0 ); if( pt_array == null || ( size = pt_array.GetSize() ) == 0 ) return null; pt_array.SetStart(); for( int i=0; i, staring with the start_index to skip the first // button which already contains the select button. // The palette buttons are created by copying an empty template button. // Parameters: // palette_name Name of the object palette to add buttons to. // button_name Base name of the object palette buttons. // start_index Number of buttons to skip (the first button // with the select icon is already in the palette). ////////////////////////////////////////////////////////////////////////// void FillObjectPalette( String palette_name, String button_name, int start_index ) { GlgObject palette = Viewport.GetResourceObject( "ObjectPalette" ); // Find and store an empty palette button used as a template. // Search the button at the top viewport level, since palette's // HasResources=NO. ButtonTemplate = Viewport.GetResourceObject( button_name + start_index ); if( ButtonTemplate == null ) { SetError( "Can't find palette button to copy!" ); return; } // Delete the template button from the palette but keep it around. palette.DeleteObject( ButtonTemplate ); // Store NumRows and NumColumns info. NumRows = ButtonTemplate.GetDResource( "NumRows" ).intValue(); NumColumns = ButtonTemplate.GetDResource( "NumColumns" ).intValue(); // Add all icons from each array, increasing the start_index. */ start_index = FillObjectPaletteFromArray( palette, button_name, start_index, LinkIconArray, LinkObjectArray, "Link" ); start_index = FillObjectPaletteFromArray( palette, button_name, start_index, NodeIconArray, NodeObjectArray, "Node" ); // Store the point marker template. SelectedMarker = PaletteTemplate.GetResourceObject( "PointMarker" ); // Cleanup ButtonTemplate = null; PaletteTemplate = null; NodeIconArray = null; LinkIconArray = null; } ////////////////////////////////////////////////////////////////////////// // Adds object palette buttons containing all icons from an array. // icon_array is an array of icon objects to use in the palette button. // object_array is an array of objects to use in the drawing. ////////////////////////////////////////////////////////////////////////// int FillObjectPaletteFromArray( GlgObject palette, String button_name, int start_index, GlgObject icon_array, GlgObject object_array, String default_tooltip ) { // Add all icons from the icon array to the palette using a copy of // the template button. int size = icon_array.GetSize(); int button_index = start_index; for( int i=0; i