Hide

SftTree/DLL 7.5 - Tree Control

Display
Print

CellEditing Sample (C)

This sample illustrates cell editing using an edit control and a combo box, with cell navigation and restricted cells.

The source code is located at C:\Program Files (x86)\Softelvdm\SftTree DLL 7.5\Samples\C\CellEditing\CellEditing.c or C:\Program Files\Softelvdm\SftTree DLL 7.5\Samples\C\CellEditing\CellEditing.c (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 <windows.h>

#include "SftTree.h"                     /* SftTree/DLL Header File */

#include "resource.h"                    // resource IDs

/**********************************************************************/
/*                              Globals                               */
/**********************************************************************/

#define IDC_TREE    100                 /* Tree control ID */
#define IDC_EDIT    101                 // Control ID for the edit control
#define IDC_COMBO   102                 // Control ID for the edit control

HINSTANCE g_hInst;                      // App Instance Handle
HWND g_hwndTree;                        /* Tree control */

// Miscellaneous bitmaps
SFT_PICTURE m_aThreeItemPictures[3];    /* Three default item pictures, see SetPictures in online help */
//SFT_PICTURE m_OtherItemPicture;       /* Another item picture, see SetItemPicture in online help */
HBITMAP m_hCellBitmap;                  /* A cell bitmap */
SFT_PICTURE m_RowColHeaderPicture;            /* Row/column picture */

/**********************************************************************/
/*                         Tree Edit Routines                         */
/**********************************************************************/

int m_editIndex;                         /* Index of (last) item being edited */
int m_editCol;                           /* Column # being edited */
HWND m_hwndEdit;                         /* Edit control used for editing */
HWND m_hwndCombo;                        /* Combo box control used for editing */

BOOL _inline CellEditing() { return m_hwndEdit || m_hwndCombo; }  // returns True if we're still editing

/* Start editing in response to a                          */
/* SFTTREEN_LBUTTONDOWN_TEXT notification.                 */

/* Edit a specific cell.                                   */

static void StartEdit(int index, int col)
{
    TCHAR szBuffer[100];
    RECT rect;
    int height;
    HWND EditParent;
    HFONT hFont;
    SFTTREE_CELLINFOPARM CellInfo;

    /* Make the cell completely visible */
    SftTree_MakeCellVisible(g_hwndTree, index, col);
    /* Get the location */
    if (!SftTree_GetDisplayCellRect(g_hwndTree, index, col, TRUE, &rect, NULL))
        return;

    if (SftTree_GetItemEditIgnore(g_hwndTree, index))
        return; // this item can't be edited
    CellInfo.version = 7;
    CellInfo.index = index;
    CellInfo.iCol = col;
    SftTree_GetCellInfo(g_hwndTree, &CellInfo);
    if (CellInfo.Cell.flag2 & SFTTREECELL_EDITIGNORE)
        return; // this item can't be edited

    m_editIndex = index; /* save position */
    m_editCol = col;

    SftTree_SetCurSel(g_hwndTree, index); // <<<< added:  selection follows item being edited
    SftTree_SetCaretIndex(g_hwndTree, index); // <<<< added:  selection follows item being edited

    /* Change selection style to not shown anything */
    SftTree_SetNoFocusStyle(g_hwndTree, SFTTREE_NOFOCUS_NOTHING);

    /* Copy the text found in the tree control */
    SftTree_GetTextCol(g_hwndTree, m_editIndex, m_editCol, szBuffer);

    SftTree_AdjustCellEditRect(g_hwndTree, m_editIndex, m_editCol, &rect);
    EditParent = SftTree_GetCellEditWindow(g_hwndTree, m_editIndex, m_editCol);

    // based on font height, get best height for the control used for cell editing
    hFont = (HFONT) SendMessage(g_hwndTree, WM_GETFONT, 0, 0);
    {
        int diff;
        TEXTMETRIC tm;
        HDC hDC = GetDC(NULL);
        hFont = (HFONT)SelectObject(hDC, hFont);
        GetTextMetrics(hDC, &tm); // Get Font Information
        hFont = SelectObject(hDC, hFont);
        ReleaseDC(NULL, hDC);

        diff = (tm.tmHeight + 5) - (rect.bottom-rect.top);
        InflateRect(&rect, 0, (diff+1)/2);
        height = rect.bottom-rect.top;
    }

    if (col != 1) {
        /* Create the edit control.*/
        /* Based on the tree control attributes and your preference, you may */
        /* have to adjust the rectangle used for the edit control. */

        m_hwndEdit = CreateWindow(TEXT("EDIT"), szBuffer,/* Class, Title */
                WS_CHILD|WS_BORDER|ES_LEFT|ES_AUTOHSCROLL, /* Styles */
                rect.left, rect.top, rect.right-rect.left, rect.bottom-rect.top,
                EditParent,                  /* Tree control */
                (HMENU) IDC_EDIT,            /* <-- provide unique ID */
                g_hInst,                     /* <-- provide instance handle */
                NULL);
        if (!m_hwndEdit)                     /* Failed */
            return;

        /* Set some edit control attributes */

        /* Set the font defined for cell editing */
        SendMessage(m_hwndEdit, WM_SETFONT, (WPARAM)hFont, 0L);
        /* Select all text in the edit control and display it */
        SendMessage(m_hwndEdit, EM_LIMITTEXT, 0, 80);
        SendMessage(m_hwndEdit, EM_SETSEL, 0, -1L);
        ShowWindow(m_hwndEdit, SW_SHOW);
        SetFocus(m_hwndEdit);                /* Set input focus to the control */
    } else {
        /* Create the combo box */

        m_hwndCombo = CreateWindow(TEXT("COMBOBOX"), TEXT(""),/* Class, Title */
                WS_CHILD|WS_BORDER|WS_VSCROLL|CBS_DROPDOWN|CBS_AUTOHSCROLL, /* Styles */
                rect.left, rect.top, rect.right-rect.left, (rect.bottom-rect.top) * 8,
                EditParent,                  /* Tree control */
                (HMENU) IDC_COMBO,           /* <-- provide unique ID */
                g_hInst,                     /* <-- provide instance handle */
                NULL);
        if (!m_hwndCombo)                    /* Failed */
            return;

        /* Set the font defined for cell editing */
        SendMessage(m_hwndCombo, WM_SETFONT, (WPARAM)hFont, 0L);

        // Add possible selections
        SendMessage(m_hwndCombo, CB_ADDSTRING, 0, (LPARAM)TEXT("Selection 1"));
        SendMessage(m_hwndCombo, CB_ADDSTRING, 0, (LPARAM)TEXT("Selection 2"));
        SendMessage(m_hwndCombo, CB_ADDSTRING, 0, (LPARAM)TEXT("Selection 3"));
        SetWindowText(m_hwndCombo, szBuffer);

        SendMessage(m_hwndCombo, CB_LIMITTEXT, 0, 80);
        SendMessage(m_hwndCombo, CB_SETITEMHEIGHT, -1, rect.bottom-rect.top-5);

        ShowWindow(m_hwndCombo, SW_SHOW);
        SetFocus(m_hwndCombo);                /* Set input focus to the control */
        SendMessage(m_hwndCombo, CB_SHOWDROPDOWN, TRUE, 0);
    }

    // The following has been added to support key handling while cell editing
    // It is used to define keys to be intercepted
    {
        BYTE KeyTable[256];
        SftTree_GetKeyHandling(g_hwndTree, KeyTable, NULL, NULL);
        KeyTable[VK_TAB] = (SFTTREE_HANDLEPURE|SFTTREE_HANDLESHIFT|SFTTREE_HANDLECTRL);// handle Tab key
        KeyTable[VK_RETURN] = (SFTTREE_HANDLEPURE|SFTTREE_HANDLESHIFT|SFTTREE_HANDLECTRL);// handle Return key
        KeyTable[VK_HOME] = (SFTTREE_HANDLECTRL);// handle Control+Home key
        KeyTable[VK_END] = (SFTTREE_HANDLECTRL);// handle Control+End key
        if (m_hwndCombo) {
            KeyTable[VK_UP] = 0;                // don't handle Up arrow key
            KeyTable[VK_DOWN] = 0;              // don't handle Down arrow key
        } else {
            KeyTable[VK_UP] = (SFTTREE_HANDLEPURE);// handle Up arrow key
            KeyTable[VK_DOWN] = (SFTTREE_HANDLEPURE);// handle Down arrow key
        }
        SftTree_SetKeyHandling(g_hwndTree, KeyTable);
    }

    UpdateWindow(g_hwndTree);
}

/* Quit editing in response to a SFTTREEN_QUITEDIT         */
/* notification.                                           */

static void QuitEdit(void)
{
    /* If the control has the focus, set the focus back to the */
    /* tree control after destroying the control */
    BOOL fHadFocus = (GetFocus() == m_hwndEdit || GetFocus() == m_hwndCombo);

    if (m_hwndEdit) {
        DestroyWindow(m_hwndEdit);
        m_hwndEdit = NULL;
    } else if (m_hwndCombo) {
        DestroyWindow(m_hwndCombo);
        m_hwndCombo = NULL;
    }
    /* Restore nofocus display method */
    SftTree_SetNoFocusStyle(g_hwndTree, SFTTREE_NOFOCUS_KEEPSEL);
    if (fHadFocus)
        SetFocus(g_hwndTree);        /* Back to tree control */
}

/* Validate edit data in response to a                     */
/* SFTTREEN_VALIDATEEDIT notification.                     */

static void ValidateEdit(void)
{
    TCHAR szBuffer[100];

    if (m_hwndEdit) {
        /* Get the text from the edit control */
        GetWindowText(m_hwndEdit, szBuffer, sizeof(szBuffer));

        /* Validate the data */
        if (lstrcmp(TEXT(""), szBuffer) == 0) {
            MessageBox(NULL, TEXT("Just to demonstrate data input validation, this example rejects empty cells.  Please enter some data."), TEXT("SftTree/DLL"), MB_OK|MB_TASKMODAL|MB_ICONSTOP);
            SetFocus(m_hwndEdit);
            return;
        } else {
            DestroyWindow(m_hwndEdit);
            m_hwndEdit = NULL;
        }
    } else {
        /* Get the text from the combo control */
        GetWindowText(m_hwndCombo, szBuffer, sizeof(szBuffer));

        /* Validate the data */
        if (lstrcmp(TEXT(""), szBuffer) == 0) {
            MessageBox(NULL, TEXT("Just to demonstrate data input validation, this example rejects empty cells.  Please enter some data."), TEXT("SftTree/DLL"), MB_OK|MB_TASKMODAL|MB_ICONSTOP);
            SetFocus(m_hwndCombo);
            return;
        } else {
            DestroyWindow(m_hwndCombo);
            m_hwndCombo = NULL;
        }
    }
    /* Save the data in the tree control */
    SftTree_SetTextCol(g_hwndTree, m_editIndex, m_editCol, szBuffer);
    /* Restore nofocus display method */
    SftTree_SetNoFocusStyle(g_hwndTree, SFTTREE_NOFOCUS_KEEPSEL);
}

void CellNavigation(TCHAR vKey, BYTE vMask)
{
    // Here we handle special keys to implement cell editing with
    // cell navigation. Cell navigation is not automatic, but using this
    // sample code, a sophisticated editing scheme can be easily implemented,
    // even with skipped columns, hidden columns, collapsed items, etc.
    // Keep in mind that col is a REAL column number, but we have
    // to deal in DISPLAY columns as the user may have reordered the
    // columns. When using cell navigation, we want to move through the
    // displayed columns

    // Please note that cell merging is not supported.

    int index = m_editIndex, col = m_editCol;
    int dispCol, firstDispCol, lastDispCol;
    LPSFTTREE_COLUMN_EX lpCol;
    int nCols;
    int lastShown = SftTree_GetPrevShown(g_hwndTree, -1);

    // get general information about tree control and columns
    nCols = SftTree_GetColumnsEx(g_hwndTree, &lpCol);/* Get column attributes */
    dispCol = SftTree_GetDisplayColumn(g_hwndTree, col);
    firstDispCol = SftTree_GetFirstDisplayColumn(g_hwndTree);
    lastDispCol = SftTree_GetLastDisplayColumn(g_hwndTree);

    if (vKey == VK_HOME && (vMask & SFTTREE_HANDLECTRL)) {  // Control+Home
        index = 0;
        dispCol = firstDispCol;
        vKey = VK_RIGHT; // if index/dispCol can't be edited, search a cell in this direction:
    } else if (vKey == VK_END && (vMask & SFTTREE_HANDLECTRL)) {  // Control+End
        index = SftTree_GetPrevShown(g_hwndTree, -1);
        dispCol = lastDispCol;
        vKey = VK_LEFT; // if index/dispCol can't be edited, search a cell in this direction:
    } else if ((vKey == VK_LEFT && (vMask & SFTTREE_HANDLEPURE)) || (vKey == VK_TAB && (vMask & SFTTREE_HANDLESHIFT))) { // Left Arrow or Shift+Tab
        dispCol--;
        vKey = VK_LEFT; // if index/dispCol can't be edited, search a cell in this direction:
    } else if ((vKey == VK_RIGHT || vKey == VK_TAB) && (vMask & SFTTREE_HANDLEPURE)) { // Right Arrow or Tab
        dispCol++;
        vKey = VK_RIGHT; // if index/dispCol can't be edited, search a cell in this direction:
    } else if (vKey == VK_RETURN && (vMask & SFTTREE_HANDLEPURE)) { // Return
        dispCol++;
        vKey = VK_RIGHT; // if index/dispCol can't be edited, search a cell in this direction:
    } else if (vKey == VK_UP && (vMask & SFTTREE_HANDLEPURE)) { // Up arrow
        index--;
    } else if (vKey == VK_DOWN && (vMask & SFTTREE_HANDLEPURE)) { // Down arrow
        index++;
    } else
        return; // this key is not handled

    // index, dispCol has possible cell coordinates.  If this cell can't be
    // edited, proceed in vKey direction (VK_UP,VK_LEFT,VK_DOWN,VK_RIGHT only)
    // until a suitable cell is found or until we hit m_editIndex, m_editCol.

    for ( ; ; ) {
        // position to a valid cell
        if (dispCol < firstDispCol) {
            index = SftTree_GetPrevShown(g_hwndTree, index);// try previous item
            dispCol = lastDispCol;
        }
        if (dispCol > lastDispCol) {
            index = SftTree_GetNextShown(g_hwndTree, index);// try next item
            if (index < 0)
                index = 0;
            dispCol = firstDispCol;
        }
        if (index < 0)
            index = lastShown;
        if (index > lastShown)
            index = 0;

        col = SftTree_GetRealColumn(g_hwndTree, dispCol);

        // make sure the item is shown
        if (SftTree_GetItemShown(g_hwndTree, index)) {
            // make sure the column is really displayed
            if (lpCol[col].width > 0) {

                // back at m_editIndex, m_editCol?
                if (m_editIndex == index && m_editCol == col) {
                    StartEdit(index, col);
                    return;
                }

                // check if item ignored
                if (!SftTree_GetItemEditIgnore(g_hwndTree, index)) {
                    // item not ignored
                    // check if cell ignored
                    SFTTREE_CELLINFOPARM CellInfo;
                    CellInfo.version = 7;
                    CellInfo.index = index;
                    CellInfo.iCol = col;
                    SftTree_GetCellInfo(g_hwndTree, &CellInfo);
                    if ((CellInfo.Cell.flag2 & SFTTREECELL_EDITIGNORE) == 0) {
                        // cell not ignored
                        StartEdit(index, col);
                        return;
                    }
                }
            }
        }

        // next cell
        if (vKey == VK_LEFT) {
            --dispCol;
        } else if (vKey == VK_RIGHT) {
            ++dispCol;
        } else if (vKey == VK_UP) {
            --index;
        } else if (vKey == VK_DOWN) {
            ++index;
        }
    }
}

/**********************************************************************/
/*                          Frame Window Proc                         */
/**********************************************************************/

LRESULT CALLBACK SDI_WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch (msg) {

    case WM_CREATE: {
        int i;

        g_hwndTree = CreateWindowEx(
            WS_EX_CLIENTEDGE,
            TEXT(SFTTREE_CLASS),             /* Window class */
            TEXT(""),                        /* Caption (none) */
            SFTTREESTYLE_NOTIFY |            /* Notify parent window */
            SFTTREESTYLE_LEFTBUTTONONLY |    /* Only respond to left mouse button */
            SFTTREESTYLE_SCROLL |            /* Honor WS_H/VSCROLL */
            WS_HSCROLL | WS_VSCROLL |        /* Vertical and horizontal scrollbars */
            WS_VISIBLE | WS_CHILD,           /* Visible, child window */
            0, 0, 0, 0,                      /* Location */
            hwnd,                            /* Parent window */
            (HMENU) IDC_TREE,                /* Tree control ID */
            g_hInst,                         /* Application instance */
            NULL);
        if (!g_hwndTree)
            return -1;

        /* Resources, such as bitmaps, should be loaded and must remain    */
        /* valid until the tree control is destroyed or no longer uses     */
        /* these.  For example, use DeleteObject to delete any bitmaps.    */

        SftTree_SetShowHeader(g_hwndTree, TRUE);/* Show column headers */
        /* Register the item pictures.  These pictures are used    */
        /* for all items in the tree control. All three pictures   */
        /* must be the same size.                                  */
        Sft_InitPicture(&m_aThreeItemPictures[0]);
        Sft_InitPicture(&m_aThreeItemPictures[1]);
        Sft_InitPicture(&m_aThreeItemPictures[2]);
        Sft_SetPictureBitmap(&m_aThreeItemPictures[0], LoadBitmap(g_hInst, MAKEINTRESOURCE(IDB_EXPANDABLE)));/* Expandable picture */
        Sft_SetPictureBitmap(&m_aThreeItemPictures[1], LoadBitmap(g_hInst, MAKEINTRESOURCE(IDB_EXPANDED)));/* Expanded picture */
        Sft_SetPictureBitmap(&m_aThreeItemPictures[2], LoadBitmap(g_hInst, MAKEINTRESOURCE(IDB_LEAF)));/* Leaf picture */
        SftTree_SetPictures(g_hwndTree, m_aThreeItemPictures);/* Use item picture */
        /* Override individual item pictures using: */
        // Sft_InitPicture(&m_OtherItemPicture);
        // Sft_SetPictureBitmap(m_OtherItemPicture, LoadBitmap(app_instance, MAKEINTRESOURCE(IDB_your_bitmap)));/* Item picture */
        // SftTree_SetItemPicture(g_hwndTree, index, m_OtherItemPicture);/* Set an item bitmap */
        SftTree_SetItemPictureAlign(g_hwndTree, TRUE);/* Align item bitmaps */
        /* Register the cell picture size.  All cell pictures used */
        /* must be the same size.  Only one picture needs to be    */
        /* registered, even if several are used.                   */
        {
            SFTTREE_CELLINFOPARM CellInfo;
            CellInfo.version = 7;
            CellInfo.index = -1;             /* Registering picture size */
            m_hCellBitmap = LoadBitmap(g_hInst, MAKEINTRESOURCE(IDB_SMILE1));/* Cell picture */
            Sft_InitPicture(&CellInfo.Cell.CellPicture1);
            Sft_SetPictureBitmap(&CellInfo.Cell.CellPicture1, m_hCellBitmap);
            SftTree_SetCellInfo(g_hwndTree, &CellInfo);/* Register use of cell pictures */
            /* Set individual cell pictures using this sample code: */
            // SFTTREE_CELLINFOPARM CellInfo;
            // CellInfo.version = 7;
            // CellInfo.index = cell_index_to_change;
            // CellInfo.iCol = column_number_to_change;
            // SftTree_GetCellInfo(g_hwndTree, &CellInfo);
            // /* m_hCellBitmap = LoadBitmap(app_instance, MAKEINTRESOURCE(IDB_your_bitmap)); *//* Cell bitmap */
            // Sft_SetPictureBitmap(&CellInfo.Cell.CellPicture1, m_hCellBitmap);
            // CellInfo.Cell.flag = SFTTREE_BMP_RIGHT;
            // SftTree_SetCellInfo(g_hwndTree, &CellInfo);
        }

        SftTree_SetTreeLineStyle(g_hwndTree, SFTTREE_TREELINE_AUTOMATIC0);/* Dotted tree lines (incl. level 0) */
        SftTree_SetShowButtons(g_hwndTree, TRUE);/* Expand/collapse buttons (level 1..n) */
        SftTree_SetShowButton0(g_hwndTree, TRUE);/* Show expand/collapse buttons (level 0) */
        SftTree_SetButtons(g_hwndTree, SFTTREE_BUTTON_AUTOMATIC3);/* Automatic button style 3 */
        SftTree_SetShowGrid(g_hwndTree, TRUE);/* Show grid */
        SftTree_SetGridStyle(g_hwndTree, SFTTREE_GRID_BOTH_DOT);/* Dotted grid lines */
        SftTree_SetShowTruncated(g_hwndTree, TRUE);/* Show ... if truncated */
        SftTree_SetSelectionStyle(g_hwndTree, SFTTREE_SELECTION_CELL1 | SFTTREE_SELECTION_OUTLINE);/* Select first cell only using outline */
        SftTree_SetSelectionArea(g_hwndTree, SFTTREE_SELECTIONAREA_ALLCELLS);/* Selection changes by clicking on an item's cells */
        SftTree_SetUpdateCaretExpandCollapse(g_hwndTree, FALSE);/* don't update caret location when expand/collapse button clicked */
        SftTree_SetFlyby(g_hwndTree, TRUE);  /* Flyby highlighting */
        SftTree_SetScrollTips(g_hwndTree, TRUE);/* Show Scrolltips */
        SftTree_SetInheritBgColor(g_hwndTree, TRUE);/* Inherit background color of first cell */
        SftTree_SetReorderColumns(g_hwndTree, TRUE);/* Column reordering */
        SftTree_SetOpenEnded(g_hwndTree, TRUE);/* Last column width */
        SftTree_SetShowHeaderButtons(g_hwndTree, TRUE);/* Show column header as buttons */

        /* Define columns */
        {
            SFTTREE_COLUMN_EX aCol[3] = {
              { 0, 0,                        /* Reserved */
                221,                         /* Width (in pixels) */
                ES_LEFT | SFTTREE_TOOLTIP,   /* Cell alignment */
                ES_LEFT | SFTTREE_HEADER_UP, /* Title style */
                TEXT("First Column"),        /* 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 */
              },
              { 0, 0,                        /* Reserved */
                253,                         /* Width (in pixels) */
                ES_LEFT | SFTTREE_TOOLTIP,   /* Cell alignment */
                ES_LEFT | SFTTREE_HEADER_UP, /* Title style */
                TEXT("Second Column"),       /* 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) */
                1,                           /* Display column number (display position) */
                0,                           /* Column flag */
                0,                           /* Minimum column width */
              },
              { 0, 0,                        /* Reserved */
                100,                         /* Width (in pixels) */
                ES_LEFT | SFTTREE_TOOLTIP,   /* Cell alignment */
                ES_LEFT | SFTTREE_HEADER_UP, /* Title style */
                TEXT("Third Column"),        /* 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) */
                2,                           /* Display column number (display position) */
                0,                           /* Column flag */
                0,                           /* Minimum column width */
              }
            };
            SftTree_SetColumnsEx(g_hwndTree, 3, aCol);/* Set column attributes */
        }

        SftTree_SetShowRowHeader(g_hwndTree, SFTTREE_ROWSTYLE_BUTTONCOUNT1);/* Row style */
        SftTree_SetRowColHeaderText(g_hwndTree, TEXT("?"));/* Row/column header text */
        SftTree_SetRowColHeaderStyle(g_hwndTree, ES_LEFT | SFTTREE_HEADER_UP);/* Row/column header style */
        Sft_InitPicture(&m_RowColHeaderPicture);
        Sft_SetPictureBitmap(&m_RowColHeaderPicture, LoadBitmap(g_hInst, MAKEINTRESOURCE(IDB_SMILE1)));/* Row/column header picture */
        SftTree_SetRowColHeaderPicture(g_hwndTree, &m_RowColHeaderPicture);/* Row/column picture */
        SftTree_SetRowColHeaderPictureStyle(g_hwndTree, SFTTREE_BMP_RIGHT);/* Row/column picture alignment */
        SftTree_SetCharSearchMode(g_hwndTree, SFTTREE_CHARSEARCH_ALLCHARSWRAP2, -1);/* Consider all characters typed, find next item, wrap around, don't expand */
        /* Change the default colors */
        {
            SFTTREE_COLORS Colors;
            SftTree_GetCtlColors(g_hwndTree, &Colors);/* Get current color settings */
            Colors.colorTreeLines = COLOR_3DDKSHADOW | 0x80000000L;/* Tree line color */
            Colors.colorSelBgNoFocus = COLOR_BTNFACE | 0x80000000L;/* Selection background color (no input focus) */
            Colors.colorSelFgNoFocus = COLOR_BTNTEXT | 0x80000000L;/* Selection foreground color (no input focus) */
            SftTree_SetCtlColors(g_hwndTree, &Colors);/* Set new colors */
        }

        /*------------------------------------------------------------------------------*/
        /* Add a few items.                                                             */
        /*------------------------------------------------------------------------------*/

        {
            int index;
            index = SftTree_AddString(g_hwndTree, TEXT("Click on a cell to edit"));/* Add an item */
            SftTree_SetTextCol(g_hwndTree, index, 1, TEXT("Use Tab/Return keys"));/* Set text in next column */
            SftTree_SetTextCol(g_hwndTree, index, 2, TEXT("Use arrow keys"));/* Set text in next column */
            index = SftTree_AddString(g_hwndTree, TEXT("This sample supports cell navigation"));/* Add an item */
            SftTree_SetTextCol(g_hwndTree, index, 1, TEXT("Ctrl+Home and Ctrl+End"));/* Set text in next column */
        }

        for (i = 0 ; i < 50 ; ++i) {
            int index;

            index = SftTree_AddString(g_hwndTree, TEXT("An item"));/* Add an item */
            SftTree_SetTextCol(g_hwndTree, index, 1, TEXT("2nd Column"));/* Set text in next column */
            SftTree_SetTextCol(g_hwndTree, index, 2, TEXT("3rd Column"));/* Set text in next column */

            index = SftTree_AddString(g_hwndTree, TEXT("Another item"));/* Add another item */
            SftTree_SetTextCol(g_hwndTree, index, 1, TEXT("2nd Column"));/* Set text in next column */
            SftTree_SetTextCol(g_hwndTree, index, 2, TEXT("3rd Column"));/* Set text in next column */
            SftTree_SetItemLevel(g_hwndTree, index, 1);/* change level */

            index = SftTree_AddString(g_hwndTree, TEXT("This item can't be edited"));/* Add another item */
            SftTree_SetItemEditIgnore(g_hwndTree, index, TRUE);
            SftTree_SetItemLevel(g_hwndTree, index, 2);/* change level */
            SftTree_SetTextCol(g_hwndTree, index, 1, TEXT("2nd Column (can't edit this item)"));/* Set text in next column */
            SftTree_SetTextCol(g_hwndTree, index, 2, TEXT("3rd Column (can't edit this item)"));/* Set text in next column */

            index = SftTree_AddString(g_hwndTree, TEXT("A fourth item"));/* Add another item */
            SftTree_SetItemLevel(g_hwndTree, index, 1);/* change level */
            SftTree_SetTextCol(g_hwndTree, index, 1, TEXT("This cell can't be edited"));/* Set text in next column */
            {
                SFTTREE_CELLINFOPARM CellInfo;
                CellInfo.version = 7;
                CellInfo.index = index;
                CellInfo.iCol = 1;
                SftTree_GetCellInfo(g_hwndTree, &CellInfo);
                CellInfo.Cell.flag2 |= SFTTREECELL_EDITIGNORE; // can't edit this column
                SftTree_SetCellInfo(g_hwndTree, &CellInfo);
            }
            SftTree_SetTextCol(g_hwndTree, index, 2, TEXT("3rd Column"));/* Set text in next column */

            /* Set a cell bitmap */
            {
                SFTTREE_CELLINFOPARM CellInfo;
                CellInfo.version = 7;
                CellInfo.index = index;
                CellInfo.iCol = 1;
                SftTree_GetCellInfo(g_hwndTree, &CellInfo);
                Sft_SetPictureBitmap(&CellInfo.Cell.CellPicture1, m_hCellBitmap);
                SftTree_SetCellInfo(g_hwndTree, &CellInfo);
            }
        }

    /*------------------------------------------------------------------------------*/
    /* Once ALL TREE CONTROL ITEMS HAVE BEEN ADDED, you can set additional tree     */
    /* control attributes.                                                          */
    /*------------------------------------------------------------------------------*/

        /* Make all column widths optimal, so text and pictures    */
        /* are not clipped horizontally.                           */
        SftTree_MakeColumnOptimal(g_hwndTree, -1);/* Make column widths optimal */

        /* Make row header width optimal, so text and pictures are */
        /* not clipped horizontally.                               */
        SftTree_MakeRowHeaderOptimal(g_hwndTree);/* Make row header width optimal */

        SftTree_RecalcHorizontalExtent(g_hwndTree);/* Update horizontal scroll bar */

        SftTree_SetCurSel(g_hwndTree, 0); /* select the first item */
        SftTree_SetCaretIndex(g_hwndTree, 0); /* and make it current */

        return 0;
     }
    case WM_DESTROY:
        QuitEdit();

        DeleteObject(m_aThreeItemPictures[0].Picture.hBitmap);/* Default item pictures */
        DeleteObject(m_aThreeItemPictures[1].Picture.hBitmap);
        DeleteObject(m_aThreeItemPictures[2].Picture.hBitmap);
        //DeleteObject(m_OtherItemPicture.Picture.hBitmap);/* Another item picture */

        DeleteObject(m_hCellBitmap);         /* A cell picture */

        DeleteObject(m_RowColHeaderPicture.Picture.hBitmap);/* Row/column picture */

        if (g_hwndTree)
            DestroyWindow(g_hwndTree);
        PostQuitMessage(0);
        break;

    case WM_SIZE: {
        int cx = LOWORD(lParam);
        int cy = HIWORD(lParam);
        SetWindowPos(g_hwndTree, NULL, 0, 0, cx, cy, SWP_NOACTIVATE | SWP_NOZORDER);
        return 0;
     }

    case WM_SETFOCUS:
        if (g_hwndTree)
            SetFocus(g_hwndTree);
        break;

    case WM_COMMAND: {
        HWND hwndCtl = (HWND) lParam;
        int id = LOWORD(wParam);
        int code = HIWORD(wParam);
        switch (id) {
        case IDC_TREE:
            switch(code) {
            case SFTTREEN_LBUTTONDBLCLK_TEXT:
            case SFTTREEN_LBUTTONDOWN_BUTTON:
            case SFTTREEN_LBUTTONDBLCLK_BUTTON: {
                int index;
                BOOL fExpand, fControl;
                /* Get current position */
                index = SftTree_GetExpandCollapseIndex(hwndCtl);/* Get caret location */
                /* Check if item is expanded */
                fExpand = SftTree_GetItemExpand(hwndCtl, index);
                /* If the CONTROL key is pressed, expand all dependent levels */
                fControl = (BOOL)(GetKeyState(VK_CONTROL)&0x8000);
                if (fExpand)
                    SftTree_Collapse(hwndCtl, index, TRUE);
                else
                    SftTree_Expand(hwndCtl, index, TRUE, fControl);
                break;
             }
            case SFTTREEN_EXPANDALL: { // expand all
                int index;
                index = SftTree_GetExpandCollapseIndex(hwndCtl);/* Get item to expand/collapse */
                SftTree_Expand(hwndCtl, index, TRUE, TRUE);
                break;
             }
            case SFTTREEN_LBUTTONDBLCLK_COLUMNRES: {
                /* Resize column optimally */
                int realCol = SftTree_GetResizeColumn(g_hwndTree);
                if (realCol >= 0) {
                    SftTree_MakeColumnOptimal(g_hwndTree, realCol);/* Make column width optimal */
                    SftTree_RecalcHorizontalExtent(g_hwndTree);/* Update horizontal scroll bar */
                }
                break;
              }
            case SFTTREEN_LBUTTONDOWN_TEXT: {
                /* Edit the current cell */
                /* Get cell to edit (honors cell merging) */
                int index, col;
                index = SftTree_GetCaretIndex(g_hwndTree);/* Get item index */
                col = SftTree_GetCaretColumn(g_hwndTree);/* Get column number */
                StartEdit(index, col);
                break;
             }
            case SFTTREEN_QUITEDIT:
                /* Abandon editing */
                QuitEdit();
                break;
            case SFTTREEN_VALIDATEEDIT:
                /* Validate input data */
                ValidateEdit();
                break;

            // The following has been added to support key handling while cell editing
            case SFTTREEN_KEYINTERCEPTED: {
                TCHAR vKey;
                BYTE vMask;
                SftTree_GetKeyHandling(g_hwndTree, NULL, &vKey, &vMask);
                switch (vKey) {
                case VK_TAB:            // Tab key
                case VK_RETURN:         // Return key
                case VK_UP:             // Up arrow key
                case VK_DOWN:           // Down arrow key
                case VK_HOME:           // Home key
                case VK_END:            // End key
                    ValidateEdit();     // validate the contents
                    if (CellEditing())  // we're still editing (validation failed)
                        break;
                    CellNavigation(vKey, vMask);
                    break;
                }
                break;
             }
            }
            break;

        case 1000:                      // Menu command, Exit
            DestroyWindow(hwnd);
            break;

        case IDCANCEL:                  // ESC has hit while editing
            QuitEdit();
            break;
        }
        break;
     }
    }
    return DefWindowProc(hwnd, msg, wParam, lParam);
}

/**********************************************************************/
/*                              WinMain                               */
/**********************************************************************/

int PASCAL WinMain(HINSTANCE hinst, HINSTANCE hinstPrev, LPSTR lpszCmdLine, int cmdShow)
{
    MSG msg;
    HWND hwndMain;

    // Initialize
    g_hInst = hinst;

    if (!hinstPrev) {
        WNDCLASS cls;

        cls.hCursor         = LoadCursor(NULL, IDC_ARROW);
        cls.hIcon           = LoadIcon(g_hInst, MAKEINTRESOURCE(IDI_ICON1));
        cls.lpszMenuName    = MAKEINTRESOURCE(IDR_MAINMENU);
        cls.hInstance       = g_hInst;
        cls.lpszClassName   = TEXT("SoftelSampleFrame");
        cls.hbrBackground   = (HBRUSH)(COLOR_WINDOW+1);
        cls.lpfnWndProc     = (WNDPROC) SDI_WndProc;
        cls.style           = CS_DBLCLKS;
        cls.cbWndExtra      = 0;
        cls.cbClsExtra      = 0;
        if (!RegisterClass(&cls))
            return 0;
    }

    SftTree_RegisterApp(hinst);   /* Register with SftTree/DLL */

    // Initialize, run, and terminate the application
    hwndMain = CreateWindowEx(
            0L,
            TEXT("SoftelSampleFrame"),
            TEXT("Softel vdm, Inc. - CellEditing Sample"),
            WS_OVERLAPPEDWINDOW | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
            CW_USEDEFAULT, CW_USEDEFAULT,
            CW_USEDEFAULT, CW_USEDEFAULT,
            NULL,
            NULL,
            g_hInst,
            NULL);
    if (!hwndMain)
        return 0;

    ShowWindow(hwndMain, cmdShow);
    UpdateWindow(hwndMain);

    while (GetMessage(&msg, NULL, 0, 0)) {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    SftTree_UnregisterApp(hinst); /* Unregister from SftTree/DLL */

    return (int) msg.wParam;
}