Chapter 6:
Processing Selections


 

User selections in a graph are made by the detection of a mouse click on a chart object. During the chart drawing process a detection node (detnode) is created for each object on the screen. A detnode describes the object, e.g. its position on the screen, series and group number, color, font, line size, object type, etc. Detnodes are created for all the objects on the chart, title, frame, risers, legend, grid lines, areas, etc. The detnode is passed to a selection list API to add the object to the selection list. A selection list is a linked list of objects selected by the user. This allows the user to use SHIFT-left-click to keep adding objects to the selection list and modify an attribute to effect all selected objects. This chapter describes the process of building and manipulating detection nodes and selections lists:

 

Detection Nodes

 

Selection Lists

 

The Detection Nodes are the internal data structures that the system uses to keep track of and manage objects in the graph. While you have access to these data structures through some API functions, it is not recommended. Selection Lists are the application's equivalent data structures that you can use to keep track of and manage objects in the graph. A complete set of API functions is available to help you create and manage selection lists and the objects they represent.

NOTE:

If your application does not draw the graph to a display or memory device, Detection Nodes are not created. Also note that you may disable this feature entirely by calling DESetDrawProcs (pDE, DE_PROCS_DRAWING_ONLY) after the call to DESetPortInfo(). This mechanism is not necessary if your application does not allow user interaction with the graph.

 

DETECTION NODES

 

SELECTION LIST

 

 

Creating a Selection List

 

 

Creating Selection Items

 

 

Managing Selection Items

 

 

Managing a Selection List

 

 

Getting Information from a Selection List

 

 

Deleting a Selection List

 

SUMMARY

 

 

Detecting User Selections

 

 

Highlighting a Selected Object

DETECTION NODES

 

Detection Nodes (also called DetNodes) are a linked list of data structures that define each element in a graph. Anytime your application calls the DrawTheGraph() or DryRunTheGraph() API function, the system will create a new linked-list of detection node records (DetNodeRec) -- one record for each object in the graph. A DetNodeRec is not created for objects that are made invisible (e.g., see the A_SHOW_... and A2D_SHOW... attributes). There is only one DetNodeList and the system maintains exclusive control of it. It is never made available to the application. The DetNodeList keeps track of all of the DetNodeRecs that were created after the most recent DrawTheGraph() or DryRunTheGraph():

 

 

Each DetNodeRec completely defines an object in the graph -- its virtual coordinates, object ID, series and groupID (where applicable), color, etc. See PGSDK API Guide for a complete description of this data structure. As objects in the graph are selected (mouse-clicked), moved, modified, or manipulated in any way, the system keeps track of the current status of the object in each DetNodeRec. With each call to DrawTheGraph() or DryRunTheGraph(), the system destroys the old DetNodeList and DetNodeRecs and creates a new DetNodeList and a complete new set of DetNodeRecs.

 

While you have access to each DetNodeRec through API functions, it is not recommended and it is a less efficient method of using the library. The recommended and more efficient procedure is through the use of Selection Lists (SelList) and Selection Items (SelItem) which provide you with a reference into each DetNodeRec.

 

See the PGSDK API Guide for a complete description of each of the data structures referenced here.

SELECTION LIST

 

Selection Lists are created and maintained by your application using the library's API functions. A Selection List (SelList) is a linked list of Selection Items. Each Selection Item record (SelItem) defines an object in the graph and includes all the information your application needs to manipulate the object. Each SelItem contains information from and a reference to the object's DetNodeRec. Your application can create multiple selection lists for a chart -- limited by the amount of memory available your application's environment. The library does all the dirty work for you through the use of the API functions. Many objects in the graph can be added to a selection list. This allows you to select multiple objects and perform actions on all of them with a single API function. For example, the following API function will set all line objects in the selection list at gpList to the color specified at aRGB[i]:

 

SetGraphAttrSL(gpGraph,gpList,A_LINECOLOR_RGB,&aRGB[i]);

 

The Selection Lists and the Selection Items they contain are created and maintained in your application. It is your application's responsibility to determine when an object in the graph has been selected (mouse-clicked) and to provide that information to the library in the form of a request for a new Selection Item in your list. Your application is responsible for creating, maintaining, and destroying the Selection List and Selection Items in the list. The API functions that are used to complete these tasks are described in the following paragraphs. All API functions that create and manage the Selection Lists are named with a "Select_" prefix (e.g., Select_AllocList, Select_AddItem, etc.). These API functions and the SelList and SelItem data structures are described in the PGSDK API Guide.

Creating a Selection List

 

The Select_AllocList() function is used to create a Selection List. The prototype is shown below:

 

SelListPtr Select_AllocList ( void );

Example:

/* Create new empty selection list */
if ( ! ( gpList = Select_AllocList() ) )
{
     /* if failure, post a message */
     MessageBox ( NULL,
          "Unable to allocate selection list",
          "WinMain",
          MB_OK | MB_ICONHAND | MB_SYSTEMMODAL );
     return FALSE;
}

 

When successfully executed, this function will return a pointer to the newly created selection list. This pointer is required as input to all other Selection Item and Selection List API functions to identify the Selection List to be manipulated. Your application must free the list when it is no longer needed. See the Select_FreeList API function later in this chapter.

Creating Selection Items

 

There are three methods that can be used to add items to a selection list. The first method adds an individual item/object definition to the Selection List based on a mouse-clicked object. The following steps are required to complete this process:

 

Get the device coordinates of the mouse location

 

Use the dvPoint() function to convert the device coordinates to virtual coordinates

 

Use the FindDetNode() function to get a reference to the DetNodeRec for the object at the virtual coordinates set by dvPoint()

 

Use the Select_AddItem() function to create a new SelItem record and add it to your selection list.

 

The following example source code illustrates this method of adding a single, selected object/item to a selection list:

 

/*draw environment pointer created by AllocDrawEnvPtr()*/
DrawEnvPtr gpDrawEnv;
/* graph pointer created by AllocGraphPtr()*/     
GraphPtr gpGraph;
/* selection list pointer created by Select_AllocList()*/
SelListPtr gpList;
SelItemPtr gpSelItem; /* selection item */
DetNodeRef gDetNode;  /* global DetNode */

 

case WM_LBUTTONDOWN;
{
     /* Get the mouse pointer */
     pt = MAKEPOINT (lParam);
     /* convert mouse coordinate to virtual coordinate */
     dvPoint(gpDrawEnv,&pt);
     /* look for detnode/object def at this coordinate */
     if (FindDetNode (gpGraph, &pt, &gDetNode))
     /* add detnode object to selection list */
     gpSelItem=Select_AddItem(gpGraph,gpList,&gDetNode);
     break;
}

 

The second method of adding items/objects to a selection list adds all detection node records (DetNodeRec) to the selection list. This method essentially creates a selection list that contains all objects in the graph as shown in the following example:

 

/* loop to find each DetNodeRec that intersect point pt */
do
{
     bFoundItem=FindNextDetNode(
          gpGraph,&pt,gpDetNode, bFoundItem);
     /* Make selection list item for each found record */
     if ( bFoundItem )      
          gpSellItem = Select_AddItem ( gpGraph,
          gpList, gpDetNode );
} while ( bFoundItem );

 

The third method of adding items/objects to a selection list is to programmatically "get" a detnode by specifying which chart object you want as shown in the following example.

 

/*PG - get the DetNode of the frame */
GetDetNode(gpGraph,O5D_FRAME,NULL_SERIESID,
     NULL_GROUPID,-3,gpDetNode);
/*PG- Turn Detnode into Sel.Item */
pTempItem = Select_AddItem(gpGraph,gpList,gpDetNode);
/*Get the bounds of the frame */
FrameRect = pTempItem->rcBounds;

Managing Selection Items

 

After a Selection List has been created and Selection Items added to it, the following functions can be used to manipulate the items/objects in:

 

Select_CalcHandlesItem(); Make sizing handles for an item

 

Select_DrawXORItem(); Highlight/Unhighlight item

 

Select_CalcHandlesList(); Make sizing handles for all items in a list

 

Select_DrawXORList(); Turn On/Off Highlight for all items in a list

 

Select_RemoveItem(); Remove an item from a selection list

 

These functions are described in the following paragraphs. Also see the Get/SetGraphAttrSI() and Get/SetGraphAttrSL() functions in Chapter 7 for a description of setting object attributes in a Selection List.

 

Select_CalcHandlesItem: This function calculates moving/sizing handles for the bounding rectangle of a given selection item/object:

 

INT16 Select_CalcHandlesItem (
     /* Pointer to Draw Environment */
     DrawEnvPtr pDE,
     /* Ptr to an Item in a Selection List */
     SelItemPtr pItem
);

 

The input parameter pDE is a pointer to a draw environment created by AllocDrawEnvPtr(). The pSelList parameter is a pointer to a selection list created by Select_AllocList().

 

Note that moving/sizing handles are only created for moveable/sizeable items (i.e., graph title, graph subtitle, footnote, etc.).

 

Select_DrawXorItem: This function draws the moving/sizing handles calculated by Select_CalcHandlesItem(). A solid XOR line is drawn around non-movable objects. Acting as a toggle, it will highlight/un-highlight any item in a selection list.

 

INT16 Select_DrawXorItem (
     /* Pointer to a Draw Environment */
     DrawEnvPtr pDE,
     /* Ptr to an Item in a Selection List */
     SelItemPtr pItem
);

 

The input parameter pDE is a pointer to a draw environment created by AllocDrawEnvPtr(). The pItem parameter is a pointer to an item in a selection list.

 

See the sample source code below for an example of how the Select_CalcHandlesItem() and Select_DrawXORItem() functions are used.

 

/* IF SHIFT KEY */
if (MK_SHIFT & wParam)
{     
     /*See if item is already in master list */
     gpSelItem = Select_SearchList(gpList, gpDetNode);
     if (gpSelItem)
     {     
          /*Call sub-routine to XOR item */
          XOR_Item(hWnd,gpSelItem);
          /*Remove this item from our list */
           Select_RemoveItem(gpList,gpSelItem);
     }

 

     else
     {
          /*Add this item to our list */
          gpSelItem = Select_AddItem(gpGraph,
               gpList,gpDetNode);
          /*Calculate Sizing Handles for item */
          Select_CalcHandlesItem(gpDrawEnv,gpSelItem);
          /* Call sub-routine to XOR item */
          XOR_Item(hWnd,gpSelItem);
     }
}

 

/*--------------------------------------------*\
| XOR_Item
\*--------------------------------------------*/
void NEAR PASCAL XOR_Item (HWND hWnd,SelItemPtr pItem)
{
     HDC hdc;
     /*set to normal drawing mode */
     hdc = GetDC (hWnd);
     DESetPortInfo(gpDrawEnv, hdc, DE_PORT_NORMAL);
     /* Begin PG Drawing */
     DrawBegin(gpDrawEnv);
     /* XOR boundaries of item in selection list */
     Select_DrawXorItem(gpDrawEnv, pItem);
     DrawEnd(gpDrawEnv); /*- End Drawing */
     ReleaseDC (hWnd,hdc);
}

 

Select_CalcHandlesList: This function calculates moving/sizing handles for the bounding rectangle of all items/object in selection a list.

 

INT16 Select_CalcHandlesList (
     /* Pointer to a Draw Environment */
     DrawEnvPtr pDE,
     /* Pointer to a Selection List */     
     SelListPtr pSelList
);     

 

The input parameter pDE is a pointer to a draw environment created by AllocDrawEnvPtr(). The pSelList parameter is a pointer to a selection list created by Select_AllocList().

 

Select_DrawXORList: This function draws XOR lines around every item in a selection list. It is basically the same as the Select_DrawXorItem() function except it will highlight/unhighlight all items in a selection list.

 

INT16 Select_DrawXorList (
     /* Pointer to a Draw Environment */
     DrawEnvPtr pDE,
     /* Pointer to a Selection List */
     SelListPtr pSelList
);     

 

The input parameter pDE is a pointer to a draw environment created by AllocDrawEnvPtr(). The pSelList parameter is a pointer to a selection list created by Select_AllocList().

 

The following example source code demonstrates how the Select_CalcHandlesList() and Select_DrawXORList() functions are used:

 

/* Match up objects in selection list with new detnodes
Select_RebuildList is necessary after DrawTheGraph()
or DryRunTheGraph()to update selection list info */
Select_RebuildList (gpGraph,gpList);
/* Calculate handles for objects in selection list
based on new detnodes*/
Select_CalcHandlesList (gpDrawEnv,gpList);
EndPaint (hWnd, &ps);
/* Call subroutine to XOR items in the list */
XOR_List(hWnd,gpList);
/*-----------------------------------------*\
| XOR_List
\*-----------------------------------------*/
void NEAR PASCAL XOR_List (HWND hWnd,SelListPtr pSelList)
{
     HDC hdc;
     hdc = GetDC (hWnd);
     DESetPortInfo(gpDrawEnv,hdc,DE_PORT_NORMAL);
     DrawBegin(gpDrawEnv);
     /* XOR boundaries of EVERY item in selection list */
     Select_DrawXorList(gpDrawEnv,pSelList);
     DrawEnd(gpDrawEnv);
     ReleaseDC (hWnd,hdc);
}

 

Select_RemoveItem: This function removes a Selection Item record (SelItem) from a selection list:

 

INT16 Select_RemoveItem (
     /*Pointer to a selection list */
     SelListPtr pSelList );
     /* Pointer to a selection item */
     SelItemPtr pItem
);

 

The input parameter pSelList is a pointer to a selection list created by Select_AllocList() and identifies the selection list from which the item is to be removed. The pItem parameter identifies the specific item to be removed. The following example code demonstrates how this function is used:

 

/* IF SHIFT KEY */
if (MK_SHIFT & wParam)
{
     /*See if item is already in master list */
     gpSelItem = Select_SearchList (gpList, gpDetNode);
      if (gpSelItem)
     {
          /*Call sub-routine to XOR item */
          XOR_Item(hWnd,gpSelItem);
          /*Remove this item from our list */
          Select_RemoveItem (gpList, gpSelItem);
     }
}

Managing a Selection List

 

The following API functions can be used to manage the selection list(s):

 

Select_ClearList(); Removes all item records from the selection list

 

Select_DuplicateList(); Makes a duplicate copy of a selection list

 

Select_RebuildList(); Rebuilds a selection list based on the current DetNode List

 

Select_ClearList: This function removes all items from a selection list. However, it does not destroy the list itself or free any memory associated with it. It simply removes the pointers to the SelItem records and frees the memory used by the selection items:

 

INT16 Select_ClearList (
     /* Pointer to a selection list */
     SelListPtr pSelList );

 

The input parameter pSelList is a pointer to a selection list created by Select_AllocList() and identifies the list to be cleared.

 

/* Un-Highlight selected items */
/* Call routine to XOR all items */
XOR_List(hWnd,gpList);
/* Clear our master list */
Select_ClearList (gpList);
/* Add this item to our list */
gpSelItem = Select_AddItem(gpGraph,gpList,gpDetNode);
/* Calculate Sizing Handles for item */
Select_CalcHandlesItem(gpDrawEnv,gpSelItem);
/* Highlight the new item */
/* Call routine to XOR this item */
XOR_Item(hWnd,gpSelItem);

 

Select_DuplicateList: This function creates a copy of a selection list.

 

SelListPtr Select_DuplicateList (
     /* Pointer to a selection list */
     SelListPtr pSelList
);

 

The input parameter pSelList is a pointer to a selection list created by Select_AllocList() and identifies the selection list to be duplicated.

 

pNewList=Select_DuplicateList(pSelList);
if (!pNewList ) return ERROR_CODE;

 

Select_RebuildList: This function recalculates selection list object IDs and locations.

 

INT16 Select_RebuildList (
     /* Pointer to a Graph */
     GraphPtr pGraph,
     /* Pointer to a selection list */
     SelListPtr pSelList
);

 

The input parameter pGraph is a pointer to a graph created by AllocGraphPtr(). The pSelList parameter is a pointer to a selection list created by Select_AllocList() and identifies the selection list to be rebuilt. After a DrawTheGraph() or DryRunTheGraph(), use the Select_RebuildList() function to ensure that only valid objects are in the selection list. If objects have been made invisible, they will no longer appear in the Selection List. Select_CalcHandlesList() and Select_DrawXorList() should also be called after Select_RebuildList() so that handles also remain valid after a graph re-draw.

 

/* DRAW THE GRAPH */
DrawBegin(gpDrawEnv);
DrawTheGraph(gpDrawEnv, gpGraph,TRUE, TRUE, TRUE);
DrawEnd(gpDrawEnv);
/* Match objects in selection list with new detnodes */
Select_RebuildList (gpGraph,gpList);
/* Calculate handles for objects in
selection list based on new detnodes*/
Select_CalcHandlesList (gpDrawEnv,gpList);

Getting Information from a Selection List

 

The following API functions can be used to get information from a Selection List:

 

Select_GetFirstItem(); Returns a pointer to the first item in a selection list.

 

Select_GetNextItem(); Returns a pointer to the next item in a selection list.

 

Select_IsEqual(); Compares two SelItem records.

 

Select_IsObjectSelected(); Determines if an ObjectID is in a selection list.

 

Select_HandleHitTest(); Determines if mouse pointer is over a sizing handle.

 

Select_GetListBounds(); Gets the boundary of a selection list.

 

Select_SearchList(); Determines if a given item is in a list.

 

Select_GetFirstItem: This function returns a pointer to the first item in a given selection list.

 

SelItemPtr Select_GetFirstItem (
     /* Pointer to a selection list */
     SelListPtr pSelList );
     /* Not Currently Used */
     INT16 goIntoGroups
);

 

The input parameter pSelList is a pointer to a selection list created by Select_AllocList().

Example:

SelItemPtr pSel;
/* Get first item in the Selection List */
pSel = Select_GetFirstItem(gpList, FALSE);

 

Select_GetNextItem: This function returns a pointer to the next selection item in a given selection list.

 

SelItemPtr Select_GetNextItem (
     /* Pointer to a selection list item */
     SelItemPtr pCurr,
     /* Not Currently Used */
     INT16 goIntoGroups
);

 

The input parameter pSelList is a pointer to a selection list created by Select_AllocList().

 

/* Look for next item in list */
pSel = Select_GetNextItem(pSel, FALSE);

 

The Select_GetFirstItem() and Select_GetNextItem() functions can be used to go through (walk) a selection list and perform a function on each item in the list. The following sample code validates each selection item pointer in a selection list:

 

BOOLEAN ValidSelItemPtr(
     SelListPtr pSelList, SelItemPtr pSelItem)
/* returns FALSE-item pointer invalid, */
/* returns TRUE-item pointer in list */
{
     /* item ptr to walk the list */
     SelItemPtr pThisItem;
     /* check the item ptr */
     if ( !pSelItem) return FALSE;
     /* for each item pointer in selection list */
     for (pThisItem=Select_GetFirstItem (
          pSelList, FALSE);
     pThisItem;
     pThisItem = Select_GetNextItem (pThisItem,
          FALSE ) )
     /* is this item pointer in question? */
     if ( pThisItem == pSelItem )
     {
          return TRUE; /* yes it is */
     }
     /* walked the whole list, couldn't locate */
     return FALSE;
}

 

Select_IsEqual: This function compares two selection list items and returns TRUE if two items are identical

 

INT16 Select_IsEqual (
     /* Pointer to a Selection List Item */
     SelItemPtr pOne,
     /* Pointer to a Selection List Item */      
     SelItemPtr pTwo
);

 

The input parameters pOne and pTwo are pointers to SelItem records in a selection list. It is not necessary that the two records reside in the same list.

 

Select_IsObjectSelected: This function determines if an object is in a selection list and returns TRUE if object is in the list.

 

INT16 Select_IsObjectSelected (
     /* Pointer to a selection list */
     SelListPtr pSelList,     
     /* Object ID */
     INT16 nObjectID
);     

 

Select_HandleHitTest: This function can be used to determine if the mouse pointer is over one of an object's moving/sizing handles. It will search the selection list for handle coordinates in a SelItem record that match the mouse coordinates identified by Point.

 

SelItemPtr Select_HandleHitTest (
     /* Pointer to a selection list */
     SelListPtr pSelList,
     /* Place to store handle number */     
     Point mousePt,
     INT16 *whichHandle,
     /* Place to store bounding rect coord*/     
     Rect *pItemRect
);     

 

If this function finds matching coordinates (i.e., mouse pointer is over a moving/sizing handle), it will set whichHandle to the handle number (0-3) and pItemRect to the virtual coordinates of the bounding rectangle. This function will return a pointer to the SelItem record where the matching coordinates were found.

 

Select_GetListBounds: This function returns the bounding rectangle for all items in selection list.

 

INT16 Select_GetListBounds (
     /* Pointer to a selection list */
     SelListPtr pSelList );
     /* Ptr to a rectangle struct to
     store bounding rectangle */
     Rect *pRect
);

 

The input parameter pSelList is a pointer to a selection list created by Select_AllocList(). The pRect parameter is a pointer to a rectangle data structure where the virtual coordinates of the resulting bounding rectangle will be stored.

Example:

Select_GetListBounds (pSelList, &rcVirt);

 

Select_SearchList: This function searches a selection list for a particular detection node reference.

 

SelItemPtr Select_SearchList (
     /* Pointer to a selection list */
     SelListPtr pSelList );     
     /*Pointer to a Detection Node */
     DetNodeRefPtr pDetRef
);

 

The input parameter pSelList is a pointer to a selection list created by Select_AllocList(). The pDetRef parameter is a pointer returned from FindDetRef(). The following example demonstrates how this function is used:

 

/* IF SHIFT KEY */
if (MK_SHIFT & wParam)
     /* See if this item is already
     in our master list */
     gpSelItem = Select_SearchList(gpList, gpDetNode);
     if (gpSelItem)
     {     /* Call subroutine to XOR item */
          XOR_Item(hWnd,gpSelItem);
          /* Remove this item from our list */
           Select_RemoveItem (gpList, gpSelItem);
     }

Deleting a Selection List

 

When your application is finished using a selection list, it must free the memory previously allocated by Select_AllocList(). Use the Select_FreeList() function to free the memory used by the selection list and any links associated with it. The prototype for this function is shown below:

 

INT16 Select_FreeList (
     /* Pointer to a selection list */
     SelListPtr pSelList
);     

Example:

/* Free Mem used by Sel List */
Select_FreeList
( gpList );
/* Free Mem used by Draw Env */
FreeDrawEnvPtr (gpDrawEnv );
/* Free Mem allocated for graph */
FreeGraphPtr ( gpGraph );
/* Close the library */
FiniTDGLIB()
return 0;

SUMMARY

 

In summary, the selection lists and selection items allow your application to determine which object(s) are selected in a chart and, based on your requirements, perform an action on one, all, or selected items in the list.

Detecting User Selections

 

The following example code illustrated how the application program can determine if an object in the graph is selected by the user/mouse button:

 

DetNodeRef gDetNode; /* DetNode */
case WM_LBUTTONDOWN:
{

 

     int i;
     POINT pt;
     /* get coordinates of mouse click */
     pt = MAKEPOINT (lParam);
     /* convert screen coordinates to virtual */
     /* coordinate system used to draw chart */
     dvPoint(gpDrawEnv,&pt);
     /* find detnode for object at that */
     /* position on the screen */

 

     if (FindDetNode(
          gpGraph,/* graph pointer */
          &pt, /* point in virtual coords */
          &gDetNode))/* pointer to detnode struct*/

 

          {
               /* add this detnode in selection list */
               gpSelItem = Select_AddItem(
                    gpGraph,/* graph pointer */
                    gpList,/* ptr to selection list */
                    &gDetNode);/* ptr to detnode struct */
          }

 

break;
}

Highlighting a Selected Object

 

This following example code illustrates how your application program can highlight items/objects in a selection list.

 

HDC hdc;
int nResult = 0;
hdc = GetDC (hwnd);/* get windows screen DC */
/* set drawing mode to normal, on screen */
DESetPortInfo(gpDrawEnv, hdc, DE_PORT_NORMAL);
/* set up the draw environment */
DrawBegin(gpDrawEnv);
/* draw XOR lines all items in selection list */
nResult = Select_DrawXorList(
     gpDrawEnv,/* env. pointer */
     gpList);/* selection list pointer */
DrawEnd(gpDrawEnv);/* finished draw env */
ReleaseDC(hWnd,hdc);/* release windows DC */