// CellEditingDlg.cpp : implementation file
//

#include "stdafx.h"
#include "CellEditing.h"
#include "CellEditingDlg.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CCellEditingDlg dialog

CCellEditingDlg::CCellEditingDlg(CWnd* pParent /*=NULL*/)
    : CDialog(CCellEditingDlg::IDD, pParent)
{
    //{{AFX_DATA_INIT(CCellEditingDlg)
        // 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);
}

void CCellEditingDlg::DoDataExchange(CDataExchange* pDX)
{
    CDialog::DoDataExchange(pDX);
    //{{AFX_DATA_MAP(CCellEditingDlg)
    DDX_Control(pDX, IDC_COMBO1, m_Combo1);
    DDX_Control(pDX, IDC_EDIT1, m_Edit1);
    DDX_Control(pDX, IDC_SFTTREE1, m_Tree);
    //}}AFX_DATA_MAP
}

BEGIN_MESSAGE_MAP(CCellEditingDlg, CDialog)
    //{{AFX_MSG_MAP(CCellEditingDlg)
    ON_WM_PAINT()
    ON_WM_QUERYDRAGICON()
    //}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CCellEditingDlg message handlers

BOOL CCellEditingDlg::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

    m_vTree = m_Tree.GetControlUnknown();
    ASSERT(m_vTree != NULL);

    long ItemIndex;
    
    ItemIndex = m_vTree->Items->Add("Click on a cell to edit");
    m_vTree->Cell[ItemIndex][1]->Text = _T("Use Tab/Return keys");
    m_vTree->Cell[ItemIndex][2]->Text = _T("Use arrow keys");
    
    ItemIndex = m_vTree->Items->Add("This sample supports cell navigation");
    m_vTree->Cell[ItemIndex][1]->Text = _T("Ctrl+Home and Ctrl+End");
    
    int i;
    for (i = 1 ; i <= 50 ; ++i) {
    
        ISftTreeItemPtr pItem;
        ISftTreeCellPtr pCell;
        
        ItemIndex = m_vTree->Items->Add(_T("An item"));
        m_vTree->Cell[ItemIndex][1]->Text = _T("2nd Column");
        m_vTree->Cell[ItemIndex][2]->Text = _T("3rd Column");
        
        ItemIndex = m_vTree->Items->Add("Another item");
        pItem = m_vTree->Item[ItemIndex];
        pItem->Level = 1;
        pItem->Cell[1]->Text = _T("2nd Column");
        pItem->Cell[2]->Text = _T("3rd Column");
    
        ItemIndex = m_vTree->Items->Add(_T("This item can't be edited"));
        pItem = m_vTree->Item[ItemIndex];
        pItem->Level = 2;
        pItem->EditIgnore = VARIANT_true;
        pItem->Cell[0]->Image->Appearance = sftImageCheckboxYes;
        pItem->Cell[1]->Text = _T("2nd Column (can't edit this item)");
        pItem->Cell[2]->Text = _T("3rd Column (can't edit this item)");
    
        ItemIndex = m_vTree->Items->Add(_T("A fourth item"));
        pItem = m_vTree->Item[ItemIndex];
        pItem->Level = 1;
        pCell = m_vTree->Cell[ItemIndex][1];
        pCell->Text = _T("This cell can't be edited");
        pCell->EditIgnore = VARIANT_true;
        pCell->Image->Appearance = sftImageCheckboxYes;
        m_vTree->Cell[ItemIndex][2]->Text = _T("3rd Column");
    
    }
    
    m_vTree->ColumnsObj->MakeOptimal();
    m_vTree->RowHeaders->MakeOptimal();
    m_vTree->Items->RecalcHorizontalExtent();

    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 CCellEditingDlg::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 CCellEditingDlg::OnQueryDragIcon()
{
    return (HCURSOR) m_hIcon;
}

void CCellEditingDlg::OnItemClickSftTree1(long ItemIndex, short ColIndex, short AreaType, short Button, short Shift) 
{
    if (AreaType == constSftTreeCellText) {
        m_vTree->Cell[ItemIndex][ColIndex]->Edit(NULL, _variant_t(0L));
    } else if (AreaType == constSftTreeCellGraphic) {
        // check if check box - toggle
        ISftPictureObjectPtr pImg;
        pImg = m_vTree->Cell[ItemIndex][ColIndex]->Image;
        if (pImg->Appearance == sftImageCheckboxNo)
            pImg->Appearance = sftImageCheckboxYes;
        else if (pImg->Appearance == sftImageCheckboxYes)
            pImg->Appearance = sftImageCheckboxNo;
    }
}

void CCellEditingDlg::OnItemDblClickSftTree1(long ItemIndex, short ColIndex, short AreaType, short Button, short Shift) 
{
    if (AreaType == constSftTreeColumnRes)
        m_vTree->Column[ColIndex]->MakeOptimal();
    else if (AreaType == constSftTreeCellGraphic) {
        // check if check box - toggle
        ISftPictureObjectPtr pImg;
        pImg = m_vTree->Cell[ItemIndex][ColIndex]->Image;
        if (pImg->Appearance == sftImageCheckboxNo)
            pImg->Appearance = sftImageCheckboxYes;
        else if (pImg->Appearance == sftImageCheckboxYes)
            pImg->Appearance = sftImageCheckboxNo;
    }
}

void CCellEditingDlg::OnToolTipVScrollSftTree1(BSTR FAR* Text, long ItemIndex, short ColIndex) 
{
    CString str;
    str.Format(_T("Item %ld - %s"), ItemIndex, (LPCTSTR)CString(*Text));
    *Text = str.AllocSysString();
}

void CCellEditingDlg::OnEditAllowedSftTree1(long ItemIndex, short ColIndex, BOOL FAR* Allowed) 
{
    // Last chance to suppress cell editing for a cell
    //if (ItemIndex == 1 && ColIndex == 1)
    //    *Allowed = VARIANT_FALSE;
}

void CCellEditingDlg::OnEditInitializingSftTree1(long FAR* Window, VARIANT FAR* vData, long EditIndex, short EditCol, long FAR* LeftPix, long FAR* TopPix, long FAR* WidthPix, long FAR* HeightPix) 
{
    HWND hwndControl;
    
    // Choose a control based on current column being edited
    if (EditCol == 1)
        hwndControl = m_Combo1.m_hWnd;
    else
        hwndControl = m_Edit1.m_hWnd;

    // LeftPix/TopPix/WidthPix/HeightPix describes the current cell area
    // we need to return the position and size needed for editing.
    // In this example, we use the height of the control on the form
    // and center it over the cell.
    CRect rect;
    if (hwndControl == m_Edit1.m_hWnd)
        m_Edit1.GetWindowRect(&rect);
    else
        m_Combo1.GetWindowRect(&rect);
    *TopPix = *TopPix + (*HeightPix - rect.Height()) / 2;
    *HeightPix = rect.Height();

    // Set the text in the control used for cell editing and
    // set other control-specific properties
    CString str((LPCWSTR) m_vTree->Cell[EditIndex][EditCol]->Text);
    if (hwndControl == m_Edit1.m_hWnd) {
        m_Edit1.SetWindowText(str);
        m_Edit1.SetSel(0, -1, FALSE);
    } else {
        m_Combo1.ResetContent();
        m_Combo1.AddString(_T("Option 1"));
        m_Combo1.AddString(_T("Option 2"));
        m_Combo1.AddString(_T("Option 3"));
        m_Combo1.AddString(str);
        m_Combo1.SetWindowText(str);
    }

    // Return the control's window handle
    *Window = (OLE_HANDLE) hwndControl;

    // Define navigation keys
    // VK_TAB
    m_vTree->CellEditIntercept(VK_TAB, (SftTreeCellEditInterceptStyleConstants) (cellEditInterceptSftTreeChar | cellEditInterceptSftTreeControlChar | cellEditInterceptSftTreeShiftChar));
    // VK_RETURN
    m_vTree->CellEditIntercept(VK_RETURN, (SftTreeCellEditInterceptStyleConstants) (cellEditInterceptSftTreeChar | cellEditInterceptSftTreeControlChar | cellEditInterceptSftTreeShiftChar));
    // VK_HOME
    m_vTree->CellEditIntercept(VK_HOME, cellEditInterceptSftTreeControlChar);
    // VK_END
    m_vTree->CellEditIntercept(VK_END, cellEditInterceptSftTreeControlChar);
    
    if (hwndControl == m_Edit1.m_hWnd) {
        // We want these keys just for the edit control.
        // VK_UP
        m_vTree->CellEditIntercept(VK_UP, (SftTreeCellEditInterceptStyleConstants) (cellEditInterceptSftTreeChar | cellEditInterceptSftTreeControlChar | cellEditInterceptSftTreeShiftChar));
        // VK_DOWN
        m_vTree->CellEditIntercept(VK_DOWN, (SftTreeCellEditInterceptStyleConstants) (cellEditInterceptSftTreeChar | cellEditInterceptSftTreeControlChar | cellEditInterceptSftTreeShiftChar));
    }
}

void CCellEditingDlg::OnEditInitializedSftTree1(long Window, const VARIANT FAR& vData, long EditIndex, short EditCol, long ParentWindow, long LeftPix, long TopPix, long WidthPix, long HeightPix, BOOL FAR* Positioned) 
{
    // Show the combo box dropdown portion
    if ((HWND)Window == m_Combo1.m_hWnd) {
        // We're taking over positioning, so we can drop down the dropdown portion of the control
        *Positioned = VARIANT_true;
        m_Combo1.MoveWindow(LeftPix, TopPix, WidthPix, HeightPix, TRUE);
        m_Combo1.EnableWindow();
        m_Combo1.ShowWindow(SW_NORMAL);
        m_Combo1.SetFocus();
        m_Combo1.ShowDropDown();
    }
}

void CCellEditingDlg::OnEditNavigatingSftTree1(long Key, short Shift, long ItemIndex, short ColIndex) 
{
    // Process key pressed
    m_vTree->EditNavigate(Key, Shift);
}

void CCellEditingDlg::OnEditValidateSftTree1(long Window, const VARIANT FAR& vData, long EditIndex, short EditCol, BOOL FAR* InputValid) 
{
    // Validate the new cell contents
    CString str;
    if ((HWND)Window == m_Edit1.m_hWnd)
        m_Edit1.GetWindowText(str);
    else
        m_Combo1.GetWindowText(str);
    str.TrimLeft();
    if (str.GetLength() <= 0) {
        AfxMessageBox(_T("Just to demonstrate data input validation, this example rejects empty cells.  Please enter some data."));
        *InputValid = VARIANT_FALSE;
    }
}

void CCellEditingDlg::OnEditEndingSftTree1(long Window, const VARIANT FAR& vData, long EditIndex, short EditCol, BOOL SaveInput) 
{
    // Save the new cell contents
    if (SaveInput) {
        CString str;
        if ((HWND)Window == m_Edit1.m_hWnd)
            m_Edit1.GetWindowText(str);
        else
            m_Combo1.GetWindowText(str);
        m_vTree->Cell[EditIndex][EditCol]->Text = _bstr_t(str);
    }
}

BEGIN_EVENTSINK_MAP(CCellEditingDlg, CDialog)
    //{{AFX_EVENTSINK_MAP(CCellEditingDlg)
    ON_EVENT(CCellEditingDlg, IDC_SFTTREE1, 4 /* ItemClick */, OnItemClickSftTree1, VTS_I4 VTS_I2 VTS_I2 VTS_I2 VTS_I2)
    ON_EVENT(CCellEditingDlg, IDC_SFTTREE1, 5 /* ItemDblClick */, OnItemDblClickSftTree1, VTS_I4 VTS_I2 VTS_I2 VTS_I2 VTS_I2)
    ON_EVENT(CCellEditingDlg, IDC_SFTTREE1, 28 /* ToolTipVScroll */, OnToolTipVScrollSftTree1, VTS_PBSTR VTS_I4 VTS_I2)
    ON_EVENT(CCellEditingDlg, IDC_SFTTREE1, 44 /* EditAllowed */, OnEditAllowedSftTree1, VTS_I4 VTS_I2 VTS_PBOOL)
    ON_EVENT(CCellEditingDlg, IDC_SFTTREE1, 38 /* EditInitializing */, OnEditInitializingSftTree1, VTS_PI4 VTS_PVARIANT VTS_I4 VTS_I2 VTS_PI4 VTS_PI4 VTS_PI4 VTS_PI4)
    ON_EVENT(CCellEditingDlg, IDC_SFTTREE1, 39 /* EditInitialized */, OnEditInitializedSftTree1, VTS_I4 VTS_VARIANT VTS_I4 VTS_I2 VTS_I4 VTS_I4 VTS_I4 VTS_I4 VTS_I4 VTS_PBOOL)
    ON_EVENT(CCellEditingDlg, IDC_SFTTREE1, 43 /* EditNavigating */, OnEditNavigatingSftTree1, VTS_I4 VTS_I2 VTS_I4 VTS_I2)
    ON_EVENT(CCellEditingDlg, IDC_SFTTREE1, 37 /* EditValidate */, OnEditValidateSftTree1, VTS_I4 VTS_VARIANT VTS_I4 VTS_I2 VTS_PBOOL)
    ON_EVENT(CCellEditingDlg, IDC_SFTTREE1, 36 /* EditEnding */, OnEditEndingSftTree1, VTS_I4 VTS_VARIANT VTS_I4 VTS_I2 VTS_BOOL)
    //}}AFX_EVENTSINK_MAP
END_EVENTSINK_MAP()