// VirtualDlg.cpp : implementation file
//

#include "stdafx.h"
#include "Virtual.h"
#include "VirtualDlg.h"

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

/////////////////////////////////////////////////////////////////////////////
// CVirtualDlg dialog

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

    m_Bitmaps.Create(IDB_BITMAPS, 16, 0, RGB(0,0,255));
    m_Worlds.Create(IDB_WORLDS, 32, 0, RGB(255,255,255));

    m_PicCount = 0;
}

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

BEGIN_MESSAGE_MAP(CVirtualDlg, CDialog)
    //{{AFX_MSG_MAP(CVirtualDlg)
    ON_WM_PAINT()
    ON_WM_QUERYDRAGICON()
    ON_WM_DESTROY()
    ON_WM_TIMER()
    //}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CVirtualDlg message handlers

BOOL CVirtualDlg::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);
    
    m_vTree->VirtualMode = VARIANT_true;
    m_vTree->VirtualCount(10000000);
    m_vTree->VirtualImageSizes(16, 16, 16, 16, 16, 16, 16, 16);
    // Make columns and row headers optimal
    // but do this at the end of the list, because our sample
    // data is larger at the end
    m_vTree->Items->TopIndex = m_vTree->Items->Count - 1;
    m_vTree->ColumnsObj->MakeOptimal();
    m_vTree->RowHeaders->MakeOptimal();
    m_vTree->Items->RecalcHorizontalExtent();
    m_vTree->Items->TopIndex = 0;

    SetTimer(TIMER_ID, 100, NULL);

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


void CVirtualDlg::OnDestroy() 
{
    KillTimer(TIMER_ID);

    CDialog::OnDestroy();
}

void CVirtualDlg::OnTimer(UINT nIDEvent) 
{
    ++m_PicCount;
    if (m_PicCount > 15)
        m_PicCount = 0;
    m_vTree->RowColumnHeader->Image->SetImageListH((OLE_HANDLE)(HIMAGELIST)m_Worlds, m_PicCount);
}

void CVirtualDlg::OnItemClickSftTree1(long ItemIndex, short ColIndex, short AreaType, short Button, short Shift) 
{
    if (AreaType == constSftTreeText)
        m_vTree->Cell[ItemIndex][ColIndex]->Edit(0, _variant_t(0L));
}

void CVirtualDlg::OnItemDblClickSftTree1(long ItemIndex, short ColIndex, short AreaType, short Button, short Shift) 
{
    if (AreaType == constSftTreeColumnRes)
        m_vTree->Column[ColIndex]->MakeOptimal();
}

void CVirtualDlg::OnVirtualItemSftTree1(long RowIndex, LPDISPATCH ItemObject) 
{
    IVirtualItemPtr pItemObj = ItemObject;
    CString str;
    str.Format(_T("Item %ld"), RowIndex);
    pItemObj->Item->Cell[0]->Text = (LPCTSTR) str;

    str.Format(_T("Cell %ld"), RowIndex);
    pItemObj->Item->Cell[1]->Text = (LPCTSTR) str;

    pItemObj->Item->Cell[2]->Text = _T("A");

    str.Format(_T("%ld"), RowIndex % 7);
    pItemObj->Item->Cell[3]->Text = (LPCTSTR) str;

    str.Format(_T("Last %ld"), RowIndex);
    pItemObj->Item->Cell[4]->Text = (LPCTSTR) str;

    str.Format(_T("R%ld"), RowIndex);
    pItemObj->Item->RowHeader->Text = (LPCTSTR) str;

    pItemObj->Item->Enabled = ((RowIndex % 2) == 0) ? VARIANT_true : VARIANT_FALSE;

    if (RowIndex % 17 == 0)
        pItemObj->Item->RowHeader->Image->SetImageListH((OLE_HANDLE)(HIMAGELIST)m_Bitmaps, (short)(RowIndex % 10));
    if (RowIndex % 3 == 0) {
        pItemObj->Item->Cell[1]->ForeColor = RGB(255,0,0);
        pItemObj->Item->Cell[1]->BackColor = RGB(255,255,255);
    }
    if (RowIndex % 5 == 0) {
        IFontPtr pFont = pItemObj->Item->Cell[1]->GetFont();
        pFont->put_Bold(TRUE);
    }
    if (RowIndex % 7 == 0) {
        pItemObj->Item->Image->SetImageListH((OLE_HANDLE)(HIMAGELIST)m_Bitmaps, (short)((RowIndex + 9) % 10));
        pItemObj->Item->LabelImage->SetImageListH((OLE_HANDLE)(HIMAGELIST)m_Bitmaps, (short)((RowIndex + 1) % 10));
    }
    if (RowIndex % 13 == 0)
        pItemObj->Item->RowHeader->Image->SetImageListH((OLE_HANDLE)(HIMAGELIST)m_Bitmaps, (short)((RowIndex + 5) % 10));
    if (RowIndex % 11 == 0)
        pItemObj->Item->RowHeader->ImageHAlign = halignSftTreeRight;
    if (RowIndex % 9 == 0)
        pItemObj->Item->Cell[1]->Image->SetImageListH((OLE_HANDLE)(HIMAGELIST)m_Bitmaps, (short)((RowIndex + 3) % 10));
    if (RowIndex % 7 == 0) {
        pItemObj->Item->Cell[0]->Image->SetImageListH((OLE_HANDLE)(HIMAGELIST)m_Bitmaps, (short)((RowIndex + 2) % 10));
        pItemObj->Item->Cell[0]->ImageHAlign = halignSftTreeRight;
    }
}

void CVirtualDlg::OnEditInitializingSftTree1(long FAR* Window, VARIANT FAR* vData, long EditIndex, short EditCol, long FAR* LeftPix, long FAR* TopPix, long FAR* WidthPix, long FAR* HeightPix) 
{
    KillTimer(TIMER_ID);

    HWND 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;
    m_Edit1.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);
    m_Edit1.SetWindowText(str);
    m_Edit1.SetSel(0, -1, FALSE);

    // 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);
    // VK_UP
    m_vTree->CellEditIntercept(VK_UP, (SftTreeCellEditInterceptStyleConstants) (cellEditInterceptSftTreeChar | cellEditInterceptSftTreeControlChar | cellEditInterceptSftTreeShiftChar));
    // VK_DOWN
    m_vTree->CellEditIntercept(VK_DOWN, (SftTreeCellEditInterceptStyleConstants) (cellEditInterceptSftTreeChar | cellEditInterceptSftTreeControlChar | cellEditInterceptSftTreeShiftChar));
}

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

void CVirtualDlg::OnEditValidateSftTree1(long Window, const VARIANT FAR& vData, long EditIndex, short EditCol, BOOL FAR* InputValid) 
{
    // Validate the new cell contents
    CString str;
    m_Edit1.GetWindowText(str);
    if (str != (LPCTSTR) m_vTree->Cell[EditIndex][EditCol]->Text)
        AfxMessageBox(_T("This example doesn't preserve the changes you make, because the sample data is randomly generated."));
}

void CVirtualDlg::OnEditEndedSftTree1(BOOL Accepted, long ItemIndex, short ColIndex) 
{
    SetTimer(TIMER_ID, 100, NULL); // restart world timer again
}

BEGIN_EVENTSINK_MAP(CVirtualDlg, CDialog)
    //{{AFX_EVENTSINK_MAP(CVirtualDlg)
    ON_EVENT(CVirtualDlg, IDC_SFTTREE1, 4 /* ItemClick */, OnItemClickSftTree1, VTS_I4 VTS_I2 VTS_I2 VTS_I2 VTS_I2)
    ON_EVENT(CVirtualDlg, IDC_SFTTREE1, 5 /* ItemDblClick */, OnItemDblClickSftTree1, VTS_I4 VTS_I2 VTS_I2 VTS_I2 VTS_I2)
    ON_EVENT(CVirtualDlg, IDC_SFTTREE1, 31 /* VirtualItem */, OnVirtualItemSftTree1, VTS_I4 VTS_DISPATCH)
    ON_EVENT(CVirtualDlg, IDC_SFTTREE1, 38 /* EditInitializing */, OnEditInitializingSftTree1, VTS_PI4 VTS_PVARIANT VTS_I4 VTS_I2 VTS_PI4 VTS_PI4 VTS_PI4 VTS_PI4)
    ON_EVENT(CVirtualDlg, IDC_SFTTREE1, 43 /* EditNavigating */, OnEditNavigatingSftTree1, VTS_I4 VTS_I2 VTS_I4 VTS_I2)
    ON_EVENT(CVirtualDlg, IDC_SFTTREE1, 37 /* EditValidate */, OnEditValidateSftTree1, VTS_I4 VTS_VARIANT VTS_I4 VTS_I2 VTS_PBOOL)
    ON_EVENT(CVirtualDlg, IDC_SFTTREE1, 40 /* EditEnded */, OnEditEndedSftTree1, VTS_BOOL VTS_I4 VTS_I2)
    //}}AFX_EVENTSINK_MAP
END_EVENTSINK_MAP()