Using Default Direct Manipulation

The Open Class Library provides default direct manipulation support for:

On OS/2, you use the left mouse button to drag objects. On Windows, you use the right mouse button to drag objects. You can use the left mouse button to drag but when the drag operation is finished, you get a pop-up menu requiring a menu choice of Copy, Move, or Cancel. On AIX, use the middle mouse button to drag objects.

Using Defaults for Entry Fields and MLEs

The default direct manipulation support for entry fields and MLEs is almost identical. When you create source items, selected text is stored within the item using the IDMItem::setContents function.

In Windows, the text must be selected in order to initiate a drag. In OS/2, all of the text is dragged if none is selected. Afterwards, the optimal rendering mechanisms and formats are determined using the length of the text characters plus any embedded characters. If the text length is fewer than or equal to 255 characters, and does not contain any embedded nulls, the text rendering format, IDM::rfText, is used. Otherwise, the shared rendering format, IDM::rfSharedMem is used.

To further optimize performance, the process rendering format, IDM::rfProcess, is added to the prior selection to handle it when the source and target entry fields or MLEs are located within the same process. If they are located within separate processes, one of the other rendering formats, is used.

The default rendering support for IDM::rfSharedMem automatically allocates the shared memory buffer and transfers the data (stored in the source item using IDMItem::setContents) from one process to another when its use is required. Therefore, the data is accessible to IDMItem::contents in the target item after the drop has occurred.

The default drag image style for the entry field and MLE support are the OLE drag cursors.

The default drag image style for the entry field and MLE support is IDM::allStacked.

The default implementation of the IDMItemProvider::provideEnterSupport function for the entry field and MLE items prevents a user from dropping text within the same window. The source and target window cannot be the same window.

When the entry field and MLE items differ, default target drop processing occurs. The entry field item retrieves the text using the IDMItem::contents function and sets the text into the entry field. The MLE item appends the text to the end of the MLE field.

Using Defaults for Containers

The default direct manipulation for containers supports moving or copying container objects within the same process. Also, all of the container views are supported. When you construct a source item, the container object is stored within the source item using the IDMItem::setObject function. Because a target can directly address a container object in the same process, you can use IDMItem::object at the target to access the container object after the drop has occurred. Therefore, the use of IDMItem::setContents and IDMItem::contents is supported if you extend the default support, but they are not used in the default implementation. Finally, the process rendering format, IDM::rfProcess, is set. This is the only RMF used for the default support.

If the user selects multiple container objects, a sequence collection is created. The source items are then stored based upon the following order:

  1. The object under the mouse pointer is stored first.
  2. The other objects are stored in the order in which IContainerControl::ObjectCursor returns them.

The default drag image style for container support is IDM::allStacked.

The default implementation of the IDMItemProvider::provideEnterSupport function for the container item prevents the user from dropping an object on a target container object if drops have been disabled by the IContainerObject::disableDrop function. Also, the IContainerControl::isMoveValid function is called to ensure that a move operation, the default, is valid.

Default target-drop processing handles both moving and copying. The default positioning of the dropped items is based upon the view of the target container. If multiple container objects are involved, IDMCnrItem::targetDrop is called once for each container item, and the items are processed in the reverse order in which they were added to the sequence collection.

When implementing container copy support, you must define an override for IContainerObject::objectCopy in the derived IContainerObject class. Also, you must define a copy constructor to be used by the override.

These are illustrated in the drag3 sample.

Enabling Default Support

You enable the default direct manipulation support for the container, entry field, and MLE by calling the desired IDMHandler static function. A pointer to the control object is supplied as the functional parameter to the static function, which performs all the required setup to enable the default support. Two samples, drag1 and drag3, are supplied to illustrate enabling default support.

Containers and windows that support direct manipulation can be the source, target, or source and target of a drag operation. This is determined by the use of the static functions IDMHandler::enableDragFrom, IDMHandler::enableDropOn, or IDMHandler::enableDragDropFor, respectively. However, notice the differences in the support for the menu bar, tool bar, and tool bar buttons.

Using Defaults for Tool Bars

The default direct manipulation for tool bars supports the dropping of menu item objects from a menu bar within the same process to create a new tool bar button. Also, moving tool bar buttons within the same process is supported: you can move and arrange tool bar buttons within the same tool bar or you can move them from another tool bar.

Deleting tool bar buttons is also supported, as you can drop the buttons on a shredder object.

On OS/2, when a source item is constructed from a menu item, the menu item resource identifier is stored within the source item using the IDMItem::setObject function, and the menu item text is stored using the IDMItem::setContents function. The process rendering format, IDM::rfProcess, is set as it is the only RMF used for the default support.

Afterwards, the IDMMenuItem constructor attempts to set the drag image based upon a stored image referenced by the resource identifier. The image can be one of the supplied Open Class Library defaults or the user can define it. If one is unavailable, a default image is used. The default drag image style for menu bar support is IDM::allStacked. The default operation is IDMOperation::link, and the drag item type is IDM::menuItem.

The Open Class Library for Windows does not support the dropping of menu item objects from a menu bar to create a new tool bar button.

Because the menu bar is only supported from a source perspective, the IDMItemProvider::provideEnterSupport and IDMItem::targetDrop functions are not implemented.

When a source item is constructed from a tool bar button, a pointer to the button window is stored within the source item. The process rendering format, IDM::rfProcess, is set, as well the shredder RMF, IDM::rmDiscard, and IDM::rfUnknown. Then, the IDMTBarButtonItem constructor sets the drag image based upon the button's stored image. The image can be one of the supplied IBM Open Class Library defaults or the user can define it. If the image is unavailable, a default image is used. The default drag image style for tool bar button support is IDM::allStacked. The default operation is IDMOperation::move, and the drag item type is IDM::toolBarButton.

The default implementation of the IDMItemProvider::provideEnterSupport function for the tool bar button item prevents the user from dropping a button on itself. It also filters the drag item types to allow drops only for the following types: IDM::toolBarButton, IDM::menuItem (OS/2 only), and IDM::bitmap. IDM::bitmap is included to allow system bitmaps to be dropped on a button. The special case of a system bitmap with a type of IDM::plainText is also handled.

Default tool bar button drop processing handles both moving and linking. The default positioning of the dropped item is based upon the position of the object over the tool bar button when it was added to the tool bar. If the new button is dropped on the left half of a tool bar button, the button is moved before the button where the drop occurred. If the new button is dropped on the right half or at the center of the tool bar button, the button is moved after the button where the drop occurred. This rule applies to every source of a drag operation, including tool bar buttons created from a menu bar, buttons within the same tool bar, and buttons from another tool bar. If the tool bar is vertical, a similar rule applies. If the new button is dropped on the lower half of a tool bar button, the new tool bar button is moved below the button where the drop occurred. If the new button is dropped on the upper half, or at the center of the tool bar button, the button is moved above the tool bar button where the drop occurred. Finally, if the item that was dropped was a system bitmap, the current tool bar button image is replaced using the system bitmap.

The tool bar only supports drop processing. The default positioning adds the tool bar button to the end of the tool bar and places it within its own group. If the source of the drag was a menu bar, a new button is created and added to the end of the tool bar. If the source of the drag was a tool bar button within the same tool bar, the button is moved to the end of the tool bar. When the source of the drag was a tool bar button in another tool bar, the button is removed from the source tool bar, and added to the end of the target tool bar.

Note: Tool bar support only works upon menu bars, tool bar buttons, and tool bars that are within the same process.

Using Rendering Mechanisms and Formats

Rendering is the process by which data is transferred from the source of a direct manipulation operation to the target. If the source and target objects are within the same process, both objects have access to the same memory address space, and the target can readily access the source data to complete the transfer. If the source and target are in separate processes, the data transfer is facilitated using a global (or shared) memory buffer and an operation that involves the dispatching and processing of rendering messages.

Renderers transfer the representation of the object being manipulated from the source object to the target object. Direct manipulation renderers manage and maintain rendering mechanisms and formats (RMFs) whose characteristics are defined by the RMF pairs that represent the data transfer method. The rendering mechanisms and formats identify the set of protocols that your items support. These renderers are objects of classes IDMSourceRenderer and IDMTargetRenderer and are derived from IDMRenderer.

When you create an IDMSourceHandler object, the Open Class Library creates a default IDMSourceRenderer. The following table displays the source RMF pairs and the corresponding drag item type. IDM::any represents any drag item type. Any object that you manipulate must have an explicit attribute that identifies the type of the item. These objects are often passed by Presentation Manager mechanisms that need to identify the attributes of an item.

Default Source Renderer

  Rendering Mechanism Rendering Format Item Type
  IDM::rmLibrary IDM::rfProcess IDM::any
  IDM::rmLibrary IDM::rfText IDM::any
  IDM::rmLibrary IDM::rfSharedMem IDM::any
  IDM::rmPrint IDM::rfUnknown IDM::any
  IDM::rmDiscard IDM::rfUnknown IDM::any
  IDM::rmFile IDM::rfUnknown IDM::any
  IDM::rmObject IDM::rfObject IDM::any

When an IDMTargetHandler object is created, the Open Class Library creates a default IDMTargetRenderer. The default target renderer RMF pairs are shown in the table below.

Default Target Renderer

  Rendering Mechanism Rendering Format Item Type
  IDM::rmLibrary IDM::rfProcess IDM::any
  IDM::rmLibrary IDM::rfText IDM::any
  IDM::rmLibrary IDM::rfSharedMem IDM::any
  IDM::rmFile IDM::rfUnknown IDM::any
  IDM::rmObject IDM::rfObject IDM::any

The Open Class Library provides IDM::rmLibrary as the rendering mechanism used for efficient drag and drop operations. The following table displays other rendering messages defined as part of the default renderers.

Other Default Rendering Mechanisms

  Rendering Mechanism Used When...
  IDM::rmPrint (OS/2 only) An Open Class Library object is dropped on a printer
  IDM::rmDiscard (OS/2 only) An Open Class Library object is dropped on the shredder
  IDM::rmFile (OS/2 only) A file is dragged from the source and dragged over or dropped on a target
  IDM::rmObject (OS/2 only) A Workplace Shell object is processed. Your application may be required to run under a Workplace Shell process to use this rendering mechanism.

Several default rendering formats are defined to assist you, theapplication developer, in using the direct manipulation classes. The following table displays these default rendering formats.

Default Rendering Formats

  Format Used When...
  IDM::rfProcess Determining if the source of the direct manipulation operation and the target are in the same process. This format must be constructed by calling the static member function IDMItem::rfForThisProcess.
  IDM::rfText Dragging text that has a length of 255 or fewer characters with no embedded null characters.
  IDM::rfSharedMem A shared memory buffer is required to transfer the data from the source to the target. This format should be used when transferring data between two separate processes and IDM::rfText cannot be used.
  IDM::rfUnknown The format is unknown.
  IDM::rfObject (OS/2 only) A Workplace Shell object is processed. Your application may be required to run under a Workplace Shell process to use this rendering format.
Note: You can use the IDM::any type to represent any drag item type.

The native renderer is the first rendering mechanism and format defined when you create the item. For example, in the declaration of the default source renderer, the native renderer supports the library rendering mechanism, the process rendering format, and any item type. In the declaration of the default target renderer, the native renderer supports the library rendering mechanism, the process rendering format, and any item type.

The following table displays the default Open Class Library RMF pairs that support target rendering.

Target RMFs

  Mechanism Format
  IDM::rmLibrary IDM::rfProcess
  IDM::rmLibrary IDM::rfText
  IDM::rmFile IDM::rfUnknown
  IDM::rmFile IDM::rfText
  IDM::rmObject IDM::rfObject

The following table displays the default Open Class Library RMF pairs that support source rendering.

Source RMFs

  Mechanism Format
  IDM::rmLibrary IDM::rfSharedMem
  IDM::rmPrint IDM::rfUnknown
  IDM::rmDiscard IDM::rfUnknown

To create renderers for controls not supported by the Open Class Library, you can create your own source or target renderer. To do this, derive from the IDMSourceRenderer or IDMTargetRenderer, create instances, and then add them to the handler using setDefaultTargetRenderer and setDefaultSourceRenderer.


Using Drag Item Types

Drag item types are useful in distinguishing drag items. Normally, the type is defined when the drag item object is constructed. IDMItem functions, such as IDMItem::setTypes and IDMItem::types, are defined to allow the setting and querying of the types, respectively.

The Open Class Library defines the following default types that you can use in your application:

 
IDM::any
Any type
IDM::binary
Generic binary item type
IDM::binaryData
Binary data item type
IDM::bitmap
Bitmap item type
IDM::container
Container item type
IDM::containerObject
Container object item type
IDM::file
File item type
IDM::icon
Icon item type
IDM::menuItem
Menu item drag item type (OS/2 only)
IDM::plainText
Plain text drag item type
IDM::text
Generic text drag item type
IDM::toolBarButton
Tool bar button drag item type
IDM::unknown
Unknown drag item type
 

You can define new types as required by your application if the preceding list does not have the types you need.


Enabling Direct Manipulation for an Entry Field or MLE

The following sample shows you how to enable direct manipulation for an entry field or an MLE control and how to use the static function, IDMHandler::enableDragDropFor. This static function creates the following:

In the following sample, the highlighted lines enable direct manipulation of text between two entry fields in the same process. Direct manipulation is enabled the same way for an MLE. The complete sample is located in the \samples\ioc\drag1 directory.

...
 26 #include <iframe.hpp>  
 27 #include <ientryfd.hpp>  
 28 #include <idmefit.hpp>  
 29 #include <idmhndlr.hpp>  
 30 #include <icoordsy.hpp>  
 31 #include "dmsamp1.h"  
 32  
 33 /*------------------------------------------------------------------------------  
 34 | main - Application Entry point                                               |  
 35 ------------------------------------------------------------------------------*/  
 36 int main()  
 37 {  
 38   ICoordinateSystem::setApplicationOrientation(  
 39           ICoordinateSystem::originLowerLeft );  
 40   
 41 /*-----------------------------------------------------------------------------|  
 42 | Create a generic frame window.                                               |  
 43 ------------------------------------------------------------------------------*/  
 44   IFrameWindow  
 45     frame( WND_MAIN );  
 46   
 47 /*-----------------------------------------------------------------------------|  
 48 | Create 2 entry fields for the client area.                                   |  
 49 ------------------------------------------------------------------------------*/  
 50   IEntryField  
 51     client( 1000, &frame, &frame ),  
 52     ext   ( 1001, &frame, &frame );  
 53  
 54 /*-----------------------------------------------------------------------------|  
 55 | Enable source and target direct manipulation support for both entry fields.  |  
 56 ------------------------------------------------------------------------------*/ 
57   IDMHandler::enableDragDropFor( &client );  58   IDMHandler::enableDragDropFor( &ext );
 59
 60 /*-----------------------------------------------------------------------------|
 61 | Frame setup - Put both entry fields in the client area, with one  added as   |
 62 | an extension.                                                                |
 63 ------------------------------------------------------------------------------*/
 64   frame
 65     .setIcon( frame.id() )
 66     .setClient( &client )
 67     .addExtension( &ext, IFrameWindow::belowClient, 0.5 )
 68     .setFocus()
 69     .show();
 70
 71 /*-----------------------------------------------------------------------------|
 72 | Run Direct Manipulation Sample 1                                             |
 73 |-----------------------------------------------------------------------------*/
 74   IApplication::current().run();
 75   return 0;
 76 }

The preceding sample illustrates how you can enable direct manipulation if you only need default entry field support. If you substitute IMultiLineEdit for IEntryField in line 50, the preceding sample then demonstrates the default MLE support.


Enabling Direct Manipulation for a Container

This section shows you how to enable direct manipulation for a container and how to use the IDMHandler static functions enableDragFrom and enableDropOn.

In the following example, the dmsamp3.hpp file defines a container control object. The .CPP file creates the container and container objects and, in the highlighted lines, calls IDMHandler::enableDragFrom and IDMHandler::enableDropOn.


 38    MySourceWin sourceWin (WND_SOURCE);
 39    MyTargetWin targetWin (WND_TARGET);
 40    IApplication::current().run();
 41    return 0;
 42 }
...
129 MySourceWin :: MySourceWin ( unsigned long windowId ) :
130                MyWindow ( windowId )
131 {
132   ITitle title (this,TITLE_SOURCE  );
133
134   /***********************************************************************/
135   /* Enable the source for dragging from (only).                         */
136   /***********************************************************************/
137   IDMHandler::enableDragFrom( cnrCtl );
138 };
139
140 /*-------------------------------------------------------------------------
141 | MyTargetWin::MyTargetWin                                    |
142 |                                                                         |
143 | Constructor.                                                            |
144 -------------------------------------------------------------------------*/
145 MyTargetWin :: MyTargetWin ( unsigned long windowId ) :
146                MyWindow ( windowId )
147 {
148   ITitle title (this, TITLE_TARGET );
149
150   /***********************************************************************/
151   /* Enable the target for dropping on (only).                           */
152   /***********************************************************************/
153   IDMHandler::enableDropOn( cnrCtl );
106 }

170 /*------------------------------------------------------------------------
171 | Customer::Customer                                                     |
172 |                                                                        |
173 | Copy constructor.                                                      |
174 ------------------------------------------------------------------------*/
175 Customer :: Customer ( const Customer &cnrobj )  :                             
176             IContainerObject ( (const IContainerObject &)cnrobj ),             
177             strName ( cnrobj.name() ),                                         
178             strAddress ( cnrobj.address() ),                                   
179             strPhone ( cnrobj.phone() ),                                       
180             myWin ( cnrobj.myWin )                                             
181 {                                                                              
182 }                                                                              

189 /*------------------------------------------------------------------------
190 | Customer::objectCopy                                                   |
191 |                                                                        |
192 | Make a copy of the Customer object.  Called by                         |
193 | IContainerObject::copyObjectTo().                                      |
194 ------------------------------------------------------------------------*/
195 IContainerObject* Customer :: objectCopy()                                     
196 {                                                                              
197   /***********************************************************************/    
198   /* Use Customer copy constructor to make a copy of the object.         */    
199   /***********************************************************************/    
200   Customer *copy = new Customer(*this);                                        
201   return((IContainerObject *)copy);                                            
202 }

Lines 81 through 84 create a source window.

Line 137 enables the window as a drag source.

Lines 145 through 148 create a target window.

Line 153 enables the window as a drop target.

Lines 175 through 182 implement the copy constructor that is used by the Customer::objectCopy function.

Lines 195 through 202 implement the IContainerObject::objectCopy override function, Customer::objectCopy.

The preceding sample illustrates how you can enable direct manipulation if you only need default container support. The complete sample is located in the \samples\ioc\drag3 directory.

The previous container example only illustrates intraprocess (source and target containers are in the same process) container support. The following sample shows interprocess (source and target containers are in separate processes) container support. The module dmsamp4.cpp contains the key logic for the drag4 sample.

Note: You must start two copies of the drag4 sample to view the interprocess support.
...
 33 /*------------------------------------------------------------------------- 
 34 | main                                                                    | 
 35 -------------------------------------------------------------------------*/ 
 36 int main( int argc, char* argv[] )                                              
 37 {                                                                                
 38    ICoordinateSystem::setApplicationOrientation(
 39          ICoordinateSystem::originLowerLeft );
 40
 41   /***********************************************************************/      
 42   /* Permit debugging during the drag                                    */
 43   /***********************************************************************/      
 44   IDM::debugSupport = true;                                                      
 45                                                                                  
 46   /***********************************************************************/      
 47   /* Create window                                                       */
 48   /***********************************************************************/      
 49   DMSample4Window                                                                
 50     frame( argv[1] );                                                            
 51                                                                                  
 52   /***********************************************************************/      
 53   /* Show it                                                             */
 54   /***********************************************************************/      
 55   frame.showModally();                                         
 56   IApplication::current().run();
 57   return 0;
 58 }                                                                                
 59                                                                                  
 60 /*------------------------------------------------------------------------- 
 61 | CustomerItem::CustomerItem                                              | 
 62 |                                                                         | 
 63 | Constructor.                                                            | 
 64 -------------------------------------------------------------------------*/ 
 65 CustomerItem :: CustomerItem ( const IDMItem::Handle& item ) :                   
 66                 IDMCnrItem ( item )                                              
 67 {                                                                                
 68   IString                                                                        
 69     rmf1 = IDMItem::rmfFrom( IDM::rmLibrary, IDM::rfSharedMem ),                 
 70     rmf2 = IDMItem::rmfFrom( IDM::rmDiscard, IDM::rfUnknown );                   
 71                                                                                  
 72   /***********************************************************************/      
 73   /* Get pointer to the associated Customer container object             */      
 74   /***********************************************************************/      
 75   Customer *pCustomer = (Customer *)object();                                    
 76                                                                                  
 77   /***********************************************************************/      
 78   /* Build and set contents.  We can only do this on the source          */      
 79   /* side.  Note that since we call this constructor on both source      */
 80   /* and target sides, we must distinguish them.  That is done           */      
 81   /* here by checking the "object" pointer.  If this constructor was     */
 82   /* called from within our generateSourceItems, then this value         */      
 83   /* will be nonzero.  If called from with the template provider's       */
 84   /* provideTargetItemFor, then it will be 0.                            */
 85   /***********************************************************************/      
 86   if (pCustomer)                                                                 
 87   {                                                                              
 88     IString                                                                      
 89       contents,                                                                  
 90       delim = '\x01';                                                            
 91                                                                                  
 92     contents += pCustomer->iconText() + delim;                                   
 93     contents += pCustomer->name() + delim;                                       
 94     contents += pCustomer->address() + delim;                                    
 95     contents += pCustomer->phone() + delim;                                      
 96     contents += pCustomer->iconId();
 97                                                                                 
 98     setContents( contents );                                                     
 99                                                                                  
100     /*********************************************************************/      
101     /* Add RMFs supported by this class (IDMCnrItem will have            */      
102     /* already specified the other RMFs we use).                         */
103     /*********************************************************************/      
104     addRMF( rmf1 );                                                              
105     addRMF( rmf2 );                                                              
106   }                                                                              
107   else                                                                           
108   {                                   
109     /*********************************************************************/      
110     /* On target side, add in <rmLibrary,rfSharedMem> if source concurs  */      
111     /* (and it's not already in there).                                  */
112     /*********************************************************************/      
113     if ((item->supportsRMF( rmf1 ))  &&                                          
114         !(supportsRMF( rmf1 )))                                                  
115     {                                                                            
116       addRMF( rmf1 );                                                            
117     }                                                                            
118   }                                                                              
119 }                                                                                
120                                                                                  
121 /*------------------------------------------------------------------------- 
122 | CustomerItem::generateSourceItems                                       | 
123 |                                                                         | 
124 | Called to give CustomerItem opportunity to attach new CustomerItem's to | 
125 | the argument IDMSourceOperation object.                                 | 
126 -------------------------------------------------------------------------*/ 
127 bool CustomerItem :: generateSourceItems ( IDMSourceOperation* pSrcOp )       
128 {                                                                                
129   /***********************************************************************/      
130   /* Get generic container items.  Note that we call the inherited       */      
131   /* function since it already has logic to deal with multiselection,    */
132   /* etc.                                                                */
133   /***********************************************************************/      
134   bool result = Inherited::generateSourceItems( pSrcOp );                     
135                                                                                  
136   /***********************************************************************/      
137   /* Now, replace each IDMCnrItem with a CustomerItem.                   */
138   /***********************************************************************/      
139   for (unsigned i = 1; i <= pSrcOp->numberOfItems(); i++)                        
140   {                                                                              
141     pSrcOp->replaceItem( i, new CustomerItem( pSrcOp->item( i ) ) );             
142   }                                                                              
143                                                                                  
144   /***********************************************************************/      
145   /* Set stack3AndFade as the default image style and set the stacking   */
146   /* percentage that is used to set the stacking offset as a percentage  */
147   /* of the image size.                                                  */
148   /***********************************************************************/
149   pSrcOp->setImageStyle( IDM::stack3AndFade );
150   pSrcOp->setStackingPercentage( IPair( 25, 25 ) );
151   return( result );
152 }
153
154 /*-------------------------------------------------------------------------
155 | CustomerItem::supportedOperationsFor                                    |
156 |                                                                         |
157 | Called when a CustomerItem is dropped on a target container.            |
158 -------------------------------------------------------------------------*/
159 unsigned long CustomerItem ::
160               supportedOperationsFor ( const IString& rmf ) const
161 {
162   if (rmf == IDMItem::rmfFrom( IDM::rmLibrary, IDM::rfSharedMem ))
163   {
164     /*********************************************************************/
165     /* If using <rmLibrary,rfSharedMem> then only copy is supported      */
166     /*********************************************************************/
167     return( IDMItem::copyable & supportedOperations() );
168   }
169
170   /***********************************************************************/
171   /* Otherwise, whatever base class supports                             */
172   /***********************************************************************/
173   return( Inherited::supportedOperationsFor( rmf ) );
174 }
175
176 /*-------------------------------------------------------------------------
177 | CustomerItem::sourceDiscard                                             |
178 |                                                                         |
179 | Called when a CustomerItem is dropped on a Workplace Shell shredder.    |
180 -------------------------------------------------------------------------*/
181 bool CustomerItem :: sourceDiscard ( IDMSourceDiscardEvent& event )
182 {
183   /***********************************************************************/
184   /* Remove the object from the container.                               */
185   /***********************************************************************/
186   IContainerControl
187    *pCnr = (IContainerControl *)(event.sourceOperation()->sourceWindow());
188   IContainerObject
189    *pCnrObj = (IContainerObject *)(object());
190
191   pCnr->removeObject( pCnrObj );
192   return( true );
193 }
194
195 /*-------------------------------------------------------------------------
196 | CustomerItem::targetDrop                                                |
197 |                                                                         |
198 | Called when a CustomerItem is dropped on a target container.            |
199 -------------------------------------------------------------------------*/
200 bool CustomerItem :: targetDrop ( IDMTargetDropEvent& event )
201 {
202   bool result = true;
203
204   /***********************************************************************/
205   /* Check if using ICLUI shared memory rendering format                 */
206   /***********************************************************************/
207   IString myRMF = IDMItem::rmfFrom( IDM::rmLibrary, IDM::rfSharedMem );
208   if (selectedRMF() == myRMF)
209   {
210     /*********************************************************************/
211     /* Yes, construct new Customer object from passed data.              */
212     /*********************************************************************/
213     IString
214       contents = this->contents(),
215       delim    = '\x01',
216       text     = contents.subString( 1, contents.indexOf( delim ) - 1 );
217
218     contents   = contents.subString( contents.indexOf( delim ) + 1 );
219     IString
220       name     = contents.subString( 1, contents.indexOf( delim ) - 1 );
221
222     contents   = contents.subString( contents.indexOf( delim ) + 1 );
223     IString
224       addr     = contents.subString( 1, contents.indexOf( delim ) - 1 );
225
226     contents   = contents.subString( contents.indexOf( delim ) + 1 );
227     IString
228       phone    = contents.subString( 1, contents.indexOf( delim ) - 1 ),
229       iconId   = contents.subString( contents.indexOf( delim ) + 1 );
230
231     IContainerControl *pCnr = event.container();
232     Customer *pNewCustomer = new Customer( text,
233                                            iconId.asUnsigned(),
234                                            name,
235                                            addr,
236                                            phone,
237                                            (MyWindow *)(pCnr->parent()) );
238
239     /*********************************************************************/
240     /* Insert the new Customer object into the container.                */
241     /*********************************************************************/
242     pCnr->addObject( pNewCustomer );
243
244     /*********************************************************************/
245     /* Create an IDMItem::Handle                                         */
246     /*                                                                   */
247     /*  We must break this into 2 statements due to a bug in the         */
248     /*  IRefCounted class.  If we use an initializer to create           */
249     /*  the handle, this sample will eventually trap due to the          */
250     /*  inability of the initializer to properly increment the           */
251     /*  drag item object use count:                                      */
252     /*  IDMItem::Handle thisHandle = this; //initializer form            */
253     /*                                                                   */
254     /*  When we break the create into 2 statements, it takes the         */
255     /*  form of an assignment which does not have the problem.           */
256     /*********************************************************************/
257     IDMItem::Handle thisHandle;
258     thisHandle = this;
259
260     /*********************************************************************/
261     /* Position the object within the container.                         */
262     /*********************************************************************/
263     IPoint pos = targetOperation()->dropPosition( thisHandle, event );
264     pCnr->moveObjectTo( pNewCustomer,
265                         0,
266                         pCnr,
267                         0,
268                         pos );
269   }
270   else
271   {
272     /*********************************************************************/
273     /* Some other RMF, base class must support it.                       */
274     /*********************************************************************/
275     result = Inherited::targetDrop( event );
276   }
277
278   return( result );
279 }
280
281 /*-------------------------------------------------------------------------
282 | DMSample4Window::DMSample4Window                                        |
283 |                                                                         |
284 | Constructor.                                                            |
285 -------------------------------------------------------------------------*/
286 DMSample4Window :: DMSample4Window ( const char* aTitle ) :
287                    MyWindow( 0 ),
288                    title( this )
289 {
290   /***********************************************************************/
291   /* Set the title.                                                      */
292   /***********************************************************************/
293   if (aTitle)
294     title.setTitleText( aTitle );
295   else
296     title.setTitleText( "Direct Manipulation Sample 4" );
297
298   /***********************************************************************/
299   /* Tailor the container.                                               */
300   /***********************************************************************/
301   this->cnrCtl->hideTitle();
302   this->cnrCtl->showIconView();
303   this->cnrCtl->arrangeIconView();
304   this->cnrCtl->setExtendedSelection();
305
306   /***********************************************************************/
307   /* Set the item provider.                                              */
308   /***********************************************************************/
309   this->cnrCtl->setItemProvider( &this->provider );
310
311   /***********************************************************************/
312   /* Enable drag/drop.                                                   */
313   /***********************************************************************/
314   IString sTitle = aTitle;
315   if (sTitle.includes( "source only" ))
316     IDMHandler::enableDragFrom( this->cnrCtl );
317   else
318   {
319     if (sTitle.includes( "target only" ))
320       IDMHandler::enableDropOn( this->cnrCtl );
321     else
322       IDMHandler::enableDragDropFor( this->cnrCtl );
323   }
324
325   /***********************************************************************/
326   /* Resize the container.                                               */
327   /***********************************************************************/
328   this->sizeTo( ISize( 250, 275 ) );
329 }

The Open Class Library's shared memory rendering format provides the interprocess support. The shared memory format uses a shared memory buffer to transfer the container object data that is stored in the source item (using IDMItem::setContents) to the target item where the data can be retrieved (using IDMItem::contents). Remember that the source item and target items are in separate processes.

Two of the functions used in the previous example, CustomerItem::sourceDiscard on lines 181 through 193 and CustomerItem::supportedOperationsFor on lines 159 through 174, need more explanation.

The sourceDiscard function demonstrates container object removal after
the user drops the object on the shredder or recycle bin. The
supportedOperationsFor function lets you determine which operation or
operations a drag item supports based upon the selected rendering mechanism
and format. For example, you could make the item
IDMItem::copyable, as shown in the preceding example, if the
selected RMF is the Open Class Library shared memory RMF. For other
RMFs, you could let the drag item default to IDMItem::moveable.

The CustomerItem constructor shown in lines 65 through 119 is generally used to construct target items because it is automatically called for target item construction when using the IDMItemProviderFor template. However, this sample shows how to use it to construct source items as well. The CustomerItem constructor uses the IDMItem::object function to determine if a source or a target item is being constructed. Line 141 in the CustomerItem::generateSourceItems function is the key, as it calls the constructor to create the source item.

Samples are provided with the Open Class Library product. Complete listings of the samples used in this chapter are included in the \samples\ioc directory unless otherwise noted. This sample is found in \samples\ioc\drag4 directory.


Setting and Querying the Drag Operation

The default operation for direct manipulation is IDMOperation::drag. The direct manipulation target determines the type of operation (for example, move, copy, or link) based upon the allowable operations defined by the item. However, you can override this setting in a derived item's IDMItem::generateSourceItems function using IDMOperation::setOperation.

Note: The target continually updates this setting, which can be dynamically manipulated using the keyboard augmentation keys. It can be queried using the IDMOperation::operation function.

If the direct manipulation source needs to determine which operation occurred at the target, the operation can be queried using the IDMSourceOperation::operation function. This is sometimes required in a derived item's IDMItem::sourceEnd function override.

For example, you could distinguish a move from a copy operation so you remove the object from the source if you were performing a move operation.


Setting the Target Emphasis

The IDMTargetEvent::presSpace and IDMTargetEvent::releasePresSpace functions are defined to assist IDMTargetEnterEvent, IDMTargetLeaveEvent, and IDMTargetDropEvent events in the drawing and removal of target emphasis. You must use these functions to acquire and release the presentation space that is used to draw target emphasis. IWindow::presSpace and IWindow::releasePresSpace do not work. The drag2 sample contains a simple implementation of target emphasis support.



Direct Manipulation


Enabling Direct Manipulation
Adding Images to Drag Items


IDMCnrItem
IDMHandler
IDMItem
IDMItemProvider
IDMItemProviderFor
IDMSourceDiscardEvent
IDMSourceOperation
IDMTargetDropEvent
IDMTargetEvent