Hide

SftTree/DLL 7.5 - Tree Control

Display
Print

DragDrop Sample (C++)

This sample illustrates drag & drop within and between tree controls.

The source code is located at C:\Program Files (x86)\Softelvdm\SftTree DLL 7.5\Samples\MFC\DragDrop\Dlg.cpp or C:\Program Files\Softelvdm\SftTree DLL 7.5\Samples\MFC\DragDrop\Dlg.cpp (on 32-bit Windows versions).

/****************************************************************************/
/* SftTree/DLL 7.5 - Tree Control for C/C++                                 */
/* Copyright (C) 1995, 2016  Softel vdm, Inc. All Rights Reserved.          */
/****************************************************************************/

#include "stdafx.h"
#include "DRAGDROP.h"
#include "Dlg.h"

/////////////////////////////////////////////////////////////////////////////
// CSampleDlg dialog

CSampleDlg::CSampleDlg(CWnd* pParent /*=NULL*/)
    : CDialog(CSampleDlg::IDD, pParent)
{
    //{{AFX_DATA_INIT(CSampleDlg)
        // NOTE: the ClassWizard will add member initialization here
    //}}AFX_DATA_INIT
    // Note that LoadIcon does not require a subsequent DestroyIcon in Win32
    m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);

    // the remembered drop target
    m_lastDropTarget = NULL;    
}

void CSampleDlg::DoDataExchange(CDataExchange* pDX)
{
    CDialog::DoDataExchange(pDX);
    //{{AFX_DATA_MAP(CSampleDlg)
        // NOTE: the ClassWizard will add DDX and DDV calls here
    //}}AFX_DATA_MAP
}

BEGIN_MESSAGE_MAP(CSampleDlg, CDialog)
    ON_SFTTREEN_LBUTTONDBLCLK_TEXT(IDC_LEFTTREE, OnLButtonExpandCollapseLeft)
    ON_SFTTREEN_LBUTTONDOWN_BUTTON(IDC_LEFTTREE, OnLButtonExpandCollapseLeft)
    ON_SFTTREEN_LBUTTONDBLCLK_BUTTON(IDC_LEFTTREE, OnLButtonExpandCollapseLeft)
    ON_SFTTREEN_EXPANDALL(IDC_LEFTTREE, OnExpandAllLeft)
    ON_SFTTREEN_AUTOEXPANDING(IDC_LEFTTREE, OnAutoExpandLeft)
    ON_SFTTREEN_ENDDRAG(IDC_LEFTTREE, OnEndDragLeft)
    ON_SFTTREEN_BEGINDRAG(IDC_LEFTTREE, OnDraggingLeft)
    ON_SFTTREEN_DRAGGING(IDC_LEFTTREE, OnDraggingLeft)
    ON_SFTTREEN_CANCELDRAG(IDC_LEFTTREE, OnCancelDrag)
    ON_SFTTREEN_LBUTTONDBLCLK_TEXT(IDC_RIGHTTREE, OnLButtonExpandCollapseRight)
    ON_SFTTREEN_LBUTTONDOWN_BUTTON(IDC_RIGHTTREE, OnLButtonExpandCollapseRight)
    ON_SFTTREEN_LBUTTONDBLCLK_BUTTON(IDC_RIGHTTREE, OnLButtonExpandCollapseRight)
    ON_SFTTREEN_EXPANDALL(IDC_RIGHTTREE, OnExpandAllRight)
    ON_SFTTREEN_AUTOEXPANDING(IDC_RIGHTTREE, OnAutoExpandRight)
    ON_SFTTREEN_ENDDRAG(IDC_RIGHTTREE, OnEndDragRight)
    ON_SFTTREEN_BEGINDRAG(IDC_RIGHTTREE, OnDraggingRight)
    ON_SFTTREEN_DRAGGING(IDC_RIGHTTREE, OnDraggingRight)
    ON_SFTTREEN_CANCELDRAG(IDC_RIGHTTREE, OnCancelDrag)
    //{{AFX_MSG_MAP(CSampleDlg)
    ON_WM_PAINT()
    ON_WM_QUERYDRAGICON()
    //}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CSampleDlg message handlers

BOOL CSampleDlg::OnInitDialog()
{
    CDialog::OnInitDialog();

    // Set the icon for this dialog.  The framework does this automatically
    //  when the application's main window is not a dialog
    SetIcon(m_hIcon, TRUE);         // Set big icon
    SetIcon(m_hIcon, FALSE);        // Set small icon

    // INITIALIZE the left side tree control

    /* Associate the tree control created from the dialog      */
    /* resource with the C++ object.                           */
    m_LeftTree.SubclassDlgItem(IDC_LEFTTREE, this /* parent window */);
    /* You could use DDX/DDV instead and add the following     */
    /* line to the DoDataExchange function of the tree         */
    /* control's parent window (remove the //).                */
    // DDX_Control(pDX, IDC_LEFTTREE, m_LeftTree);

    m_BgBitmap.LoadBitmap(IDB_BACKGROUND);/* Load a background bitmap */
    m_LeftTree.SetBackgroundBitmap(m_BgBitmap);/* Define the background bitmap */

    /* Register the item pictures.  These pictures are used    */
    /* for all items in the tree control. All three pictures   */
    /* must be the same size.                                  */
    {
        SFT_PICTURE aPic[3];
        Sft_InitPicture(&aPic[0]);
        Sft_InitPicture(&aPic[1]);
        Sft_InitPicture(&aPic[2]);
        m_aThreeItemBitmaps[0].LoadBitmap(IDB_EXPANDABLE);/* Expandable bitmap */
        Sft_SetPictureBitmap(&aPic[0], m_aThreeItemBitmaps[0]);/* Assign bitmap */
        m_aThreeItemBitmaps[1].LoadBitmap(IDB_EXPANDED);/* Expanded bitmap */
        Sft_SetPictureBitmap(&aPic[1], m_aThreeItemBitmaps[1]);/* Assign bitmap */
        m_aThreeItemBitmaps[2].LoadBitmap(IDB_LEAF);/* Leaf bitmap */
        Sft_SetPictureBitmap(&aPic[2], m_aThreeItemBitmaps[2]);/* Assign bitmap */
        m_LeftTree.SetPictures(aPic);    /* Use item pictures */
    }
    m_LeftTree.SetItemBitmapAlign(TRUE); /* Align item bitmaps */
    m_LeftTree.SetTreeLineStyle(SFTTREE_TREELINE_DOT0);/* Dotted tree lines (incl. level 0) */
    m_LeftTree.SetShowButtons(TRUE);     /* Expand/collapse buttons (level 1..n) */
    m_LeftTree.SetShowButton0(TRUE);     /* Show expand/collapse buttons (level 0) */
    m_LeftTree.SetButtons(SFTTREE_BUTTON_SIMPLE);/* Button style */
    m_LeftTree.SetShowTruncated(TRUE);   /* Show ... if truncated */
    m_LeftTree.SetSelectionStyle(SFTTREE_SELECTION_CELL1);/* Select first cell only */
    m_LeftTree.SetSelectionArea(SFTTREE_SELECTIONAREA_ALL);/* Selection changes by clicking anywhere on an item */
    m_LeftTree.SetFlyby(TRUE);           /* Flyby highlighting */
    m_LeftTree.SetScrollTips(TRUE);      /* Show Scrolltips */
    m_LeftTree.SetInheritBgColor(TRUE);  /* Inherit background color of first cell */
    m_LeftTree.SetOpenEnded(TRUE);       /* Last column width */
    /* Define columns */
    {
        SFTTREE_COLUMN_EX aCol[1] = {
          { 0, 0,                        /* Reserved */
            49,                          /* Width (in pixels) */
            ES_LEFT,                     /* Cell alignment */
            ES_LEFT,                     /* Title style */
            _T("Title"),                 /* Column header title */
            NULL, NULL,                  /* Reserved field and bitmap handle */
            SFTTREE_BMP_RIGHT,           /* Picture alignment */
            0, 0, 0,                     /* Reserved fields */
            SFTTREE_NOCOLOR,             /* Cell background color */
            SFTTREE_NOCOLOR,             /* Cell foreground color */
            SFTTREE_NOCOLOR,             /* Selected cell background color */
            SFTTREE_NOCOLOR,             /* Selected cell foreground color */
            0,                           /* Real column position (set by SetColumns call) */
            0,                           /* Display column number (display position) */
            0,                           /* Column flag */
            0,                           /* Minimum column width */
          }                              
        };
        m_LeftTree.SetColumns(1, aCol);  /* Set column attributes */
    }

    m_LeftTree.SetShowRowHeader(SFTTREE_ROWSTYLE_BUTTONCOUNT0);/* Row style */
    m_LeftTree.SetRowHeaderStyle(ES_LEFT | SFTTREE_HEADER_UP);/* Row header style */
    m_LeftTree.SetDragBitmaps(TRUE);     /* Allow drag & drop from item, label pictures */
    m_LeftTree.SetDragType(SFTTREE_DRAG_PIXELIMM);/* Select and move by a number of pixels to start drag */
    m_LeftTree.SetDropHighlightStyle(SFTTREE_DROPHIGHLIGHT_BETWEEN);/* Draw line to represent drop target */
    m_LeftTree.SetCharSearchMode(SFTTREE_CHARSEARCH_ALLCHARS, -1);/* Consider all characters typed */
    /* Change the default colors */
    {
        SFTTREE_COLORS Colors;
        m_LeftTree.GetCtlColors(&Colors);/* Get current color settings */
        Colors.colorSelBgNoFocus = COLOR_BTNFACE | 0x80000000L;/* Selection background color (no input focus) */
        Colors.colorSelFgNoFocus = COLOR_BTNTEXT | 0x80000000L;/* Selection foreground color (no input focus) */
        m_LeftTree.SetCtlColors(&Colors);/* Set new colors */
    }

    // Add a few items

    int index;
    for (index = 3 ; index <= 30 ; ++index) {
        int i;
        CString str;
        str.Format(_T("Item %d"), index-3);
        i = m_LeftTree.AddString(str);
        m_LeftTree.SetItemLevel(i, abs(3 - (index % 6)));
    }

    /* Make row header width optimal, so text and pictures are  */
    /* not clipped horizontally.                               */
    m_LeftTree.MakeRowHeaderOptimal(0, FALSE);/* Make row header width optimal */
    m_LeftTree.RecalcHorizontalExtent(0, FALSE);/* Update horizontal scroll bar */

    // INITIALIZE the right side tree control

    /* Associate the tree control created from the dialog      */
    /* resource with the C++ object.                           */
    m_RightTree.SubclassDlgItem(IDC_RIGHTTREE, this /* parent window */);
    /* You could use DDX/DDV instead and add the following     */
    /* line to the DoDataExchange function of the tree         */
    /* control's parent window (remove the //).                */
    // DDX_Control(pDX, IDC_RIGHTTREE, m_RightTree);


    m_RightTree.SetTreeLineStyle(SFTTREE_TREELINE_AUTOMATIC0);/* Dotted or invisible tree lines (incl. level 0) */
    m_RightTree.SetShowButtons(TRUE);    /* Expand/collapse buttons (level 1..n) */
    m_RightTree.SetShowButton0(TRUE);    /* Show expand/collapse buttons (level 0) */
    m_RightTree.SetButtons(SFTTREE_BUTTON_AUTOMATIC3);/* Automatic button style 3 */
    m_RightTree.SetShowTruncated(TRUE);  /* Show ... if truncated */
    m_RightTree.SetShowFocus(FALSE);     /* Don't show focus rectangle (caret) */
    m_RightTree.SetSelectionArea(SFTTREE_SELECTIONAREA_ALL);/* Selection changes by clicking anywhere on an item */
    m_RightTree.SetSelectionStyle(SFTTREE_SELECTION_CELL1 | SFTTREE_SELECTION_OUTLINE);/* Select first cell only using outline */
    m_RightTree.SetFlyby(TRUE);          /* Flyby highlighting */
    m_RightTree.SetScrollTips(TRUE);     /* Show Scrolltips */
    m_RightTree.SetOpenEnded(TRUE);      /* Last column width */
    /* Define columns */
    {
        SFTTREE_COLUMN_EX aCol[1] = {
          { 0, 0,                        /* Reserved */
            100,                         /* Width (in pixels) */
            ES_LEFT,                     /* Cell alignment */
            ES_LEFT,                     /* Title style */
            _T("Title"),                 /* Column header title */
            NULL, NULL,                  /* Reserved field and bitmap handle */
            SFTTREE_BMP_RIGHT,           /* Picture alignment */
            0, 0, 0,                     /* Reserved fields */
            SFTTREE_NOCOLOR,             /* Cell background color */
            SFTTREE_NOCOLOR,             /* Cell foreground color */
            SFTTREE_NOCOLOR,             /* Selected cell background color */
            SFTTREE_NOCOLOR,             /* Selected cell foreground color */
            0,                           /* Real column position (set by SetColumns call) */
            0,                           /* Display column number (display position) */
            0,                           /* Column flag */
            0,                           /* Minimum column width */
          }                              
        };
        m_RightTree.SetColumns(1, aCol); /* Set column attributes */
    }

    m_RightTree.SetDragBitmaps(TRUE);    /* Allow drag & drop from item, label pictures */
    m_RightTree.SetDragType(SFTTREE_DRAG_PIXELIMM);/* Select and move by a number of pixels to start drag */
    m_RightTree.SetDropHighlightStyle(SFTTREE_DROPHIGHLIGHT_ONTOP);/* Highlight drop target */
    m_RightTree.SetCharSearchMode(SFTTREE_CHARSEARCH_ALLCHARS, -1);/* Consider all characters typed */

    // Add a few items

    for (index = 3 ; index <= 30 ; ++index) {
        int i;
        CString str;
        str.Format(_T("Item %d"), index-3);
        i = m_RightTree.AddString(str);
        m_RightTree.SetItemLevel(i, abs(3 - (index % 6)));
    }

    m_RightTree.RecalcHorizontalExtent(0, FALSE);/* Update horizontal scroll bar */

    CenterWindow();

    return TRUE;  // return TRUE  unless you set the focus to a control
}

// If you add a minimize button to your dialog, you will need the code below
//  to draw the icon.  For MFC applications using the document/view model,
//  this is automatically done for you by the framework.

void CSampleDlg::OnPaint() 
{
    if (IsIconic())
    {
        CPaintDC dc(this); // device context for painting

        SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);

        // Center icon in client rectangle
        int cxIcon = GetSystemMetrics(SM_CXICON);
        int cyIcon = GetSystemMetrics(SM_CYICON);
        CRect rect;
        GetClientRect(&rect);
        int x = (rect.Width() - cxIcon + 1) / 2;
        int y = (rect.Height() - cyIcon + 1) / 2;

        // Draw the icon
        dc.DrawIcon(x, y, m_hIcon);
    }
    else
    {
        CDialog::OnPaint();
    }
}

// The system calls this to obtain the cursor to display while the user drags
//  the minimized window.
HCURSOR CSampleDlg::OnQueryDragIcon()
{
    return (HCURSOR) m_hIcon;
}

// LEFT SIDE TREE CONTROL EVENTS

/* Respond to expand/collapse requests as the user clicks  */
/* on different tree components.  The events handled here  */
/* can be changed to suit your application.                */

void CSampleDlg::OnLButtonExpandCollapseLeft()
{
    /* get index of item to expand/collapse */
    int index = m_LeftTree.GetExpandCollapseIndex();
    /* get current expand/collapsed status */
    BOOL fExpanded = m_LeftTree.GetItemExpand(index);
    /* if control key is used we'll expand all dependents */
    BOOL fDepth = (::GetKeyState(VK_CONTROL)&0x8000);

    if (fExpanded)
        m_LeftTree.Collapse(index, TRUE);
    else
        m_LeftTree.Expand(index, TRUE, fDepth);
}

/* Respond to numeric keypad multiply key.                 */

void CSampleDlg::OnExpandAllLeft()
{
    /* get index of item to expand/collapse */
    int index = m_LeftTree.GetExpandCollapseIndex();

   m_LeftTree.Expand(index, TRUE, TRUE);
}

void CSampleDlg::OnAutoExpandLeft()
{
    /* get index of item to expand/collapse */
    int index = m_LeftTree.GetExpandCollapseIndex();

    m_LeftTree.Expand(index, TRUE, FALSE);
}

void CSampleDlg::OnEndDragLeft()
{
    /* The user dropped something */

    LPSFTTREE_DRAGINFO lpInfo;
    int index;
    CString str, text;

    lpInfo = m_LeftTree.GetDragInfo();

    if (lpInfo->hwnd != m_LeftTree.m_hWnd) { // The target is another window

        // In this example the "other" control could be the right tree control

        if (lpInfo->hwnd == m_RightTree.m_hWnd) { // target is left tree
            index = m_RightTree.GetDropHighlight();
            text = _T("The drop target is item %d in the right tree control");
        } else {
            index = -1;
            text = _T("There is no valid drop target");
        }
    } else { // target is the right tree control
        index = m_LeftTree.GetDropHighlight();
        text = _T("The drop target is item %d in the left tree control");
    }

    // always clear drop targets.  If you forget, or do it too late,
    // the vertical scrolling may still be active
    if (m_lastDropTarget) {
        m_lastDropTarget->SetDropHighlight(-1);
        m_lastDropTarget->StopAutoExpandTimer();
    }
    m_lastDropTarget = NULL;    

    str.Format(text, index);
    AfxMessageBox(str);
}

void CSampleDlg::OnDraggingLeft()
{
    /* Drag & drop in progress, which was started on the left side tree */
    LPSFTTREE_DRAGINFO lpInfo;
    lpInfo = m_LeftTree.GetDragInfo();

    if (lpInfo->hwnd != m_LeftTree.m_hWnd) { // The target is another window

        // clear old drop target
        if (m_lastDropTarget) {
            m_lastDropTarget->SetDropHighlight(-1);
            m_lastDropTarget->StopAutoExpandTimer();
        }
        m_lastDropTarget = NULL;

        // the target is another control, we have to set the cursor and
        // also update the drop target
        // In this example the "other" control could be the right tree control

        if (lpInfo->hwnd == m_RightTree.m_hWnd) { // target is right tree

            // set the drop OK cursor
            lpInfo->fDropOK = TRUE;
            lpInfo->hCursor = AfxGetApp()->LoadCursor(IDC_DRAG);

            // update the drop target in the right tree
            CPoint pt = lpInfo->ptDrag;
            ::MapWindowPoints(HWND_DESKTOP, m_RightTree.m_hWnd, &pt, 1);
            int index = m_RightTree.CalcIndexFromPointEx(&pt);
            m_RightTree.SetDropHighlight(index, TRUE);
            m_RightTree.StartAutoExpandTimer(index, FALSE, 0);

            // remember who is the drop target
            m_lastDropTarget = &m_RightTree;
        }

    } else { // left side tree is the drop target
        // clear old drop target if different
        if (m_lastDropTarget && m_lastDropTarget != &m_LeftTree) {
            m_lastDropTarget->SetDropHighlight(-1);
            m_lastDropTarget->StopAutoExpandTimer();
        }
        m_lastDropTarget = &m_LeftTree;
        m_lastDropTarget->StartAutoExpandTimer(lpInfo->index, FALSE, 0);
    }
}

// RIGHT SIDE TREE CONTROL EVENTS

/* Respond to expand/collapse requests as the user clicks  */
/* on different tree components.  The events handled here  */
/* can be changed to suit your application.                */

void CSampleDlg::OnLButtonExpandCollapseRight()
{
    /* get index of item to expand/collapse */
    int index = m_RightTree.GetCaretIndex();
    /* get current expand/collapsed status */
    BOOL fExpanded = m_RightTree.GetItemExpand(index);
    /* if control key is used we'll expand all dependents */
    BOOL fDepth = (::GetKeyState(VK_CONTROL)&0x8000);

    if (fExpanded)
        m_RightTree.Collapse(index, TRUE);
    else
        m_RightTree.Expand(index, TRUE, fDepth);
}

/* Respond to numeric keypad multiply key.                 */

void CSampleDlg::OnExpandAllRight()
{
    /* get index of item to expand/collapse */
    int index = m_RightTree.GetExpandCollapseIndex();

   m_RightTree.Expand(index, TRUE, TRUE);
}

void CSampleDlg::OnAutoExpandRight()
{
    /* get index of item to expand/collapse */
    int index = m_RightTree.GetExpandCollapseIndex();

    m_RightTree.Expand(index, TRUE, FALSE);
}

void CSampleDlg::OnEndDragRight()
{
    /* The user dropped something */

    LPSFTTREE_DRAGINFO lpInfo;
    int index;
    CString str, text;

    lpInfo = m_RightTree.GetDragInfo();

    if (lpInfo->hwnd != m_RightTree.m_hWnd) { // The target is another window

        // In this example the "other" control could be the left tree control

        if (lpInfo->hwnd == m_LeftTree.m_hWnd) { // target is left tree
            index = m_LeftTree.GetDropHighlight();
            text = _T("The drop target is item %d in the left tree control");
        } else {
            index = -1;
            text = _T("There is no valid drop target");
        }
    } else { // target is the right tree control
        index = m_RightTree.GetDropHighlight();
        text = _T("The drop target is item %d in the right tree control");
    }

    // always clear drop targets.  If you forget, or do it too late,
    // the vertical scrolling may still be active
    if (m_lastDropTarget) {
        m_lastDropTarget->SetDropHighlight(-1);
        m_lastDropTarget->StopAutoExpandTimer();
    }
    m_lastDropTarget = NULL;    

    str.Format(text, index);
    AfxMessageBox(str);
}

void CSampleDlg::OnDraggingRight()
{
    /* Drag & drop in progress, which was started on the right side tree */
    LPSFTTREE_DRAGINFO lpInfo;
    lpInfo = m_RightTree.GetDragInfo();

    if (lpInfo->hwnd != m_RightTree.m_hWnd) { // The target is another window

        // clear old drop target
        if (m_lastDropTarget) {
            m_lastDropTarget->SetDropHighlight(-1);
            m_lastDropTarget->StopAutoExpandTimer();
        }
        m_lastDropTarget = NULL;

        // the target is another control, we have to set the cursor and
        // also update the drop target
        // In this example the "other" control could be the left tree control

        if (lpInfo->hwnd == m_LeftTree.m_hWnd) { // target is left tree

            // set the drop OK cursor
            lpInfo->fDropOK = TRUE;
            lpInfo->hCursor = AfxGetApp()->LoadCursor(IDC_DRAG);

            // update the drop target in the left tree
            CPoint pt = lpInfo->ptDrag;
            ::MapWindowPoints(HWND_DESKTOP, m_LeftTree.m_hWnd, &pt, 1);
            int index = m_LeftTree.CalcIndexFromPointEx(&pt);
            m_LeftTree.SetDropHighlight(index, TRUE);
            m_LeftTree.StartAutoExpandTimer(index, FALSE, 0);

            // remember who is the drop target
            m_lastDropTarget = &m_LeftTree;
        }

    } else { // right side tree is the drop target
        // clear old drop target if different
        if (m_lastDropTarget && m_lastDropTarget != &m_RightTree) {
            m_lastDropTarget->SetDropHighlight(-1);
            m_lastDropTarget->StopAutoExpandTimer();
        }
        m_lastDropTarget = &m_RightTree;
        m_lastDropTarget->StartAutoExpandTimer(lpInfo->index, FALSE, 0);
    }
}

void CSampleDlg::OnCancelDrag()
{
    // always clear drop targets
    if (m_lastDropTarget) {
        m_lastDropTarget->SetDropHighlight(-1); /* Visually clear drop target */
        m_lastDropTarget->StopAutoExpandTimer();
        m_lastDropTarget = NULL;    
    }
    AfxMessageBox(_T("Drag & drop cancelled."));
}