═══ 1. Introduction ═══ This document is the programmer's reference for the Direct Manipulation ListBox (DMLB) control. For more information on programming with this control, see OS/2 Developer Magazine, Nov/Dec 1995. Acknowledgments This control was originally conceived at IBM Yorktown Research by Alan Warren. The control was rewritten and enhanced by Mark McMillan of IBM, Research Triangle Park, USA. Description The Direct Manipulation ListBox is a very useful enhancement for the standard PM listbox control. It supplies the capability to support drag/drop reordering of items in a listbox, and drag/drop of items from one listbox to another. ═══ 2. Using the DMLB ═══ To add direct-manipulation capability to a standard listbox (or an MCLB), the listbox or MCLB should be created in the usual way. After the listbox control is created, the DMLBInitialize function is called to establish the DMLB subclass. The application must define the following resources in its .RC file: #include "dmlb.h" POINTER ID_DMLB_DRAGMOVE "lbdrag.ptr" POINTER ID_DMLB_DRAGCOPY "lbdragcp.ptr" POINTER ID_DMLB_DRAGNONE "nodrag.ptr" POINTER ID_DMLB_DRGNORTH "drgnorth.ptr" POINTER ID_DMLB_DRGSOUTH "drgsouth.ptr" POINTER ID_DMLB_DRGDEL "drgdel.ptr" If these resources reside an a DLL, the DLL module handle must be supplied on the DMLBInitialize call. Once the DMLB subclass is established, the application must, at a minimum, respond to the LN_DMLB_QRYDROP message. It may choose to also process other DMLB notification messages. ═══ 3. WM_CONTROL Message Reference ═══ This section describes all the WM_CONTROL messages generated by a DMLB subclassed control and sent to the control owner. Note that all of the standard LN_* messages are generated from the listbox as usual. ═══ 3.1. LN_DMLB_CONTEXT ═══ This WM_CONTROL notification is sent by the DMLB to its owner when the user has requested a context menu on the listbox. Param1 DMLBID (USHORT) ID of the DMLB listbox NotifyCode (USHORT) LN_DMLB_CONTEXT Param2 Index (SHORT) Index of the item for which the context menu was requested. This value will be LIT_NONE if the pointer was not over an item when the menu was requested. Returns Nothing Remarks The owner can respond by poping up a context menu at the current pointer coordinates or it can ignore this message if context menus are not supported. Example case WM_INITDLG: // or WM_CREATE ContextHwnd = WinLoadMenu(...); ... case WM_CONTROL: switch SHORT1FROMMP(mp1) { case ID_LISTBOX: switch (SHORT2FROMMP(mp1)) { case LN_DMLB_CONTEXT: { /* The user has requested a context menu. Short 1 of mp2 is the */ /* index of the listbox item under the pointer. */ POINTL Point; SHORT ContextIndex; ContextIndx = SHORT1FROMMP(mp2); /* Popup the context menu at the pointer position. */ WinQueryMsgPos((HAB)0, &Point); WinPopupMenu(HWND_DESKTOP, hwnd, ContextHwnd, Point.x, Point.y, 0, PU_HCONSTRAIN| PU_VCONSTRAIN PU_MOUSEBUTTON1 | PU_MOUSEBUTTON2 | PU_MOUSEBUTTON3 | PU_KEYBOARD ); return (MRESULT)TRUE; } } break; } break; /* End of WM_CONTROL */ ═══ 3.2. LN_DMLB_DELETE ═══ This WM_CONTROL notification is sent to the owner of the source listbox when a listbox item is about to be deleted as a result of a drag/drop operation. Param1 DMLBID (USHORT) ID of the DMLB listbox NotifyCode (USHORT) LN_DMLB_DELETE Param2 Target (HWND) The window handle of the target listbox on which the drop has occured. Returns Nothing Remarks This message occures when a listbox item is dropped on a listbox which returned DROPMODE_DELETE in response to a LN_DMLB_QRYDROP message. The listbox on which the drop occured is given in mp2. The item to be deleted is the currently selected item of the listbox. Note that this message does not occure when an item is moved from one listbox to another. It occures only if the item is to be deleted. This message is sent before the item is deleted giving the owner a chance to free any dynamic resources that may be associated with this item. ═══ 3.3. LN_DMLB_DELETE_MOVE ═══ This WM_CONTROL notification is sent to the owner of the source listbox when a listbox item is about to be moved to another listbox as a result of a drag/drop operation. Param1 DMLBID (USHORT) ID of the DMLB listbox NotifyCode (USHORT) LN_DMLB_DELETE_MOVE Param2 Target (HWND) The window handle of the target listbox on which the drop has occured. Returns Nothing Remarks This message occures when a listbox item is dropped on a listbox which returned DROPMODE_MOVE in response to a LN_DMLB_QRYDROP message. The listbox on which the drop occured is given in mp2. The item to be moved is the currently selected item of the listbox. Note that this message does not occure when an item is moved within the same listbox (see LN_DMLB_REORDERED). It occures only if the item is moved from this (source) listbox to another (target) listbox. When an item is moved from one listbox to another, the item text and handle are both copied to the target listbox and then the item is deleted from the source listbox. This message is sent before the item is deleted from the source listbox. ═══ 3.4. LN_DMLB_REORDERED ═══ This WM_CONTROL notification is sent by the DMLB to its owner when a listbox item is moved within the same listbox (the listbox items are reordered). Param1 DMLBID (USHORT) ID of the DMLB listbox NotifyCode (USHORT) LN_DMLB_REORDERED Param2 Target (HWND) The window handle of listbox Returns Nothing Remarks This message occures when a listbox item is dragged and dropped on the same listbox. The moved item is the currently selected item. When an item is moved the item text and item handle are copied, the item is deleted, and then the item is reinserted at a new position. ═══ 3.5. LN_DMLB_INSERT_MOVE ═══ This WM_CONTROL notification is sent to the owner of the target listbox when a listbox item inserted by being moved from another listbox. Param1 DMLBID (USHORT) ID of the DMLB listbox NotifyCode (USHORT) LN_DMLB_INSERT_MOVE Param2 Target (HWND) The window handle of the source listbox Returns Nothing Remarks This message occures when a listbox item is dragged from another listbox and dropped on this listbox. This listbox must responded with DROPMODE_MOVE to LN_DMLB_QRYDROP to receive this message. This message is sent after the insert has been completed. The inserted item is the currently selected item. This message occures before the item is deleted from the source listbox. Both the item text and item handle are copied from the source listbox. ═══ 3.6. LN_DMLB_INSERT_COPY ═══ This WM_CONTROL notification is sent to the owner of the target listbox when a listbox item inserted by being copied from another listbox. Param1 DMLBID (USHORT) ID of the DMLB listbox NotifyCode (USHORT) LN_DMLB_INSERT_COPY Param2 Target (HWND) The window handle of the source listbox Returns Nothing Remarks This message occures when a listbox item is dragged from another listbox and dropped on this listbox. This listbox must responded with DROPMODE_COPY to LN_DMLB_QRYDROP to receive this message. This message is sent after the insert has been completed. The inserted item is the currently selected item. Both the item text and item handle are copied from the source listbox. The source listbox item is not deleted. ═══ 3.7. LN_DMLB_QRYDROP ═══ This WM_CONTROL notification is sent to the owner of the target listbox when a listbox item is dragged over it. Param1 DMLBID (USHORT) ID of the DMLB listbox NotifyCode (USHORT) LN_DMLB_QRYDROP Param2 Target (HWND) The window handle of the source listbox Returns DropAllowed (BOOL) If FALSE is returned then no drop is allowed and the pointer will be set to the "no drop" shape. If TRUE is returned then a drop is allowed and the pointer shape is set according to the DropType value. DropType (SHORT) If DropAllowed is FALSE then this value is ignored. Otherwise this value indicates what action will be taken if the user completes the drop on this listbox. The possible values are: o DROPMODE_MOVE The item will be inserted into the current listbox and deleted from the source listbox. If the source and target listboxs are same a LN_DMLB_REORDERED notification message will be sent. If they are different listboxes, LN_DMLB_INSERT_MOVE will be sent to the target and LN_DMLB_DELETE_MOVE will be sent to the source. o DROPMODE_MOVE The item will be inserted into the current listbox. It will not be deleted from the source listbox. If the source and target listboxs are same the item will be duplicated in the listbox. A LN_DMLB_INSERT_COPY notification message is sent to the target listbox. No notification is sent to the source. o DROPMODE_DELETE The item will be deleted from the source listbox. It will not be inserted in the target listbox. The source listbox will receive a LN_DMLB_DELETE notification message. Remarks This message is sent to the target listbox while a drag is in progress over the listbox. The application must respond by indicating if a drop is allowed or not, and if so, what type of drop should occure (copy, move, or delete). The pointer shape will be changed to reflect the result of this message and if NoDrop is TRUE, no drop will be allowed. Note that this message does occure when a listbox item is dragged on its own listbox. Example case WM_CONTROL: switch SHORT1FROMMP(mp1) { case ID_LISTBOX: switch (SHORT2FROMMP(mp1)) { case LN_DMLB_QRYDROP: // If dropping in same listbox, move the item. If drop is // from some other listbox, refuse it. if (HWNDFROMMP(mp2) == WinWindowFromID(hwnd, ID_LISTBOX)) return MRFROM2SHORT(TRUE, DROPMODE_MOVE); return MRFROM2SHORT(FALSE, 0); ... ═══ 4. DMLB Resources ═══ The DMLB subclass requires access to several POINTER type resources to use during drag/drop operations. The application must have the following statements in its resource (.RC) file: #include "dmlb.h" POINTER ID_DMLB_DRAGMOVE "lbdrag.ptr" POINTER ID_DMLB_DRAGCOPY "lbdragcp.ptr" POINTER ID_DMLB_DRAGNONE "nodrag.ptr" POINTER ID_DMLB_DRGNORTH "drgnorth.ptr" POINTER ID_DMLB_DRGSOUTH "drgsouth.ptr" POINTER ID_DMLB_DRGDEL "drgdel.ptr" As supplied in the toolkit, these resources use POINTER IDs 9000 through 9005. Application defined POINTER resources must not conflict with these ID values. If these resources are defined in a DLL then the DLL module handle must be supplied on the DMLBInitialize call. ═══ 5. DMLBInitialize ═══ This function establishes a DMLB subclass on a standard PM listbox control. Syntax: BOOL DMLBInitialize(LBHwnd, ResHMod) ┌───────────────┬──────────┬──────────┬──────────────────────────────────────────────────┐ │Name │Type │In/Out │Description │ ├───────────────┼──────────┼──────────┼──────────────────────────────────────────────────┤ │LBHwnd │HWND │input │Handle of the listbox to be subclassed. │ ├───────────────┼──────────┼──────────┼──────────────────────────────────────────────────┤ │ResHMod │HMODULE │input │Handle of the module (DLL) the DMLB Resources are │ │ │ │ │to be retrieved from. This may be NULLHANDLE if │ │ │ │ │the sources are bound to the EXE. │ └───────────────┴──────────┴──────────┴──────────────────────────────────────────────────┘ Returns ┌───────────────┬──────────┬──────────┬──────────────────────────────────────────────────┐ │Sucess │BOOL │return │TRUE if initialization sucessful, FALSE if it │ │ │ │ │failed. │ └───────────────┴──────────┴──────────┴──────────────────────────────────────────────────┘ Remarks This function is called to setup a DMLB subclassing of a standard PM listbox control. Note that the QWL_USER window words of the listbox window will be used by the subclass for a pointer to the subclass instance data. After this function sucessfully completes, the application may use the first PVOID of the DMLB instance data. The application must have the DMLB Resources (pointers) available in a resource DLL or bound to the executable module. If the resources reside in a DLL the DLL module handle must be supplied on this call.