From 863f21995955fb3e9aa471430218967d4e642c27 Mon Sep 17 00:00:00 2001
From: mrDarker <mr.darker@163.com>
Date: 星期四, 29 五月 2025 16:11:24 +0800
Subject: [PATCH] Merge branch 'liuyang'
---
SourceCode/Bond/Servo/Servo.vcxproj | 32
SourceCode/Bond/Servo/resource.h | 0
SourceCode/Bond/Servo/Servo.vcxproj.user | 4
SourceCode/Bond/Servo/GridControl/NewCellTypes/GridURLCell.h | 55
SourceCode/Bond/Servo/GridControl/GridCell.cpp | 294 +
SourceCode/Bond/Servo/Servo.cpp | 38
SourceCode/Bond/Servo/stdafx.h | 11
SourceCode/Bond/Servo/GridControl/GridCtrl.cpp | 8428 +++++++++++++++++++++++++++++++++
SourceCode/Bond/Servo/GridControl/GridInPlaceEdit.h | 83
SourceCode/Bond/Servo/GridControl/NewCellTypes/GridCellNumeric.cpp | 42
SourceCode/Bond/Servo/PortConfigurationDlg.h | 30
SourceCode/Bond/Servo/TransferManager.cpp | 550 ++
SourceCode/Bond/Servo/GridControl/NewCellTypes/GridURLCell.cpp | 212
SourceCode/Bond/Servo/GridControl/NewCellTypes/GridCellDateTime.cpp | 268 +
SourceCode/Bond/Servo/GridControl/NewCellTypes/GridCellCheck.h | 68
SourceCode/Bond/Servo/GridControl/GridDropTarget.h | 82
SourceCode/Bond/Servo/GridControl/NewCellTypes/GridCellCombo.cpp | 510 ++
SourceCode/Bond/Servo/Servo.rc | 0
SourceCode/Bond/Servo/GridControl/CellRange.h | 156
SourceCode/Bond/Servo/GridControl/GridCell.h | 143
SourceCode/Bond/Servo/GridControl/NewCellTypes/GridCellCheck.cpp | 185
SourceCode/Bond/Servo/GridControl/GridInPlaceEdit.cpp | 262 +
SourceCode/Bond/Servo/GridControl/TitleTip.h | 87
SourceCode/Bond/Servo/GridControl/GridDropTarget.cpp | 156
SourceCode/Bond/Servo/TransferManager.h | 171
SourceCode/Bond/Servo/CPageGraph1.cpp | 6
SourceCode/Bond/Servo/GridControl/NewCellTypes/GridCellDateTime.h | 92
SourceCode/Bond/Servo/PageRobotCmd.cpp | 12
SourceCode/Bond/Servo/GridControl/GridCellButton.h | 28
SourceCode/Bond/Servo/GridControl/GridCellBase.cpp | 773 +++
SourceCode/Bond/Servo/GridControl/GridMemDC.h | 106
SourceCode/Bond/Servo/PortConfigurationDlg.cpp | 146
SourceCode/Bond/Servo/Servo.vcxproj.filters | 88
SourceCode/Bond/Servo/GridControl/NewCellTypes/GridCellNumeric.h | 26
SourceCode/Bond/Servo/GridControl/NewCellTypes/GridCellCombo.h | 178
SourceCode/Bond/Servo/CEFEM.cpp | 14
SourceCode/Bond/Servo/GridControl/GridCellBase.h | 172
SourceCode/Bond/Servo/GridControl/GridCellButton.cpp | 46
SourceCode/Bond/Servo/GridControl/GridCtrl.h | 1090 ++++
SourceCode/Bond/Servo/GridControl/TitleTip.cpp | 341 +
40 files changed, 14,949 insertions(+), 36 deletions(-)
diff --git a/SourceCode/Bond/Servo/CEFEM.cpp b/SourceCode/Bond/Servo/CEFEM.cpp
index 05e7074..ddaba81 100644
--- a/SourceCode/Bond/Servo/CEFEM.cpp
+++ b/SourceCode/Bond/Servo/CEFEM.cpp
@@ -409,7 +409,7 @@
// eq cim mode change
CEqCimModeChangeStep* pStep = new CEqCimModeChangeStep();
pStep->setName(STEP_CIM_MODE_CHANGE);
- pStep->setWriteSignalDev(0x70);
+ pStep->setWriteSignalDev(0x60);
pStep->setCimModeDev(0x15);
if (addStep(STEP_ID_CIMMODE_CHANGED_CMD_REPLY, pStep) != 0) {
delete pStep;
@@ -420,7 +420,7 @@
// eq cim message
CEqCimMessageCmdStep* pStep = new CEqCimMessageCmdStep();
pStep->setName(STEP_CIM_MESSAGE_CMD);
- pStep->setWriteSignalDev(0x71);
+ pStep->setWriteSignalDev(0x61);
pStep->setCimMessageDev(0x0);
if (addStep(STEP_ID_CIM_MSG_SET_CMD_REPLY, pStep) != 0) {
delete pStep;
@@ -432,7 +432,7 @@
// CIM Message Confirm
CEqReadIntStep* pStep = new CEqReadIntStep(__INT32, 0x5f80);
pStep->setName(STEP_EQ_CIM_MESSAGE_CONFIRM);
- pStep->setWriteSignalDev(0x59);
+ pStep->setWriteSignalDev(0x49);
if (addStep(STEP_ID_CIM_MSG_CONFIRM_REPORT, pStep) != 0) {
delete pStep;
}
@@ -460,7 +460,7 @@
// eq cim message clear
CEqCimMessageClearStep* pStep = new CEqCimMessageClearStep();
pStep->setName(STEP_CIM_MESSAGE_CLEAR);
- pStep->setWriteSignalDev(0x72);
+ pStep->setWriteSignalDev(0x62);
pStep->setClearCimMessageDev(0x13);
if (addStep(STEP_ID_CIM_MSG_CLEAR_CMD_REPLY, pStep) != 0) {
delete pStep;
@@ -471,7 +471,7 @@
// datetime set cmd
CEqDateTimeSetCmdStep* pStep = new CEqDateTimeSetCmdStep();
pStep->setName(STEP_DATETIME_SET_CMD);
- pStep->setWriteSignalDev(0x73);
+ pStep->setWriteSignalDev(0x63);
pStep->setDateTimeDev(0x16);
if (addStep(STEP_ID_DATETIME_SET_CMD_REPLY, pStep) != 0) {
delete pStep;
@@ -482,7 +482,7 @@
// vcr enable
CEqVCREnableStep* pStep = new CEqVCREnableStep();
pStep->setName(STEP_EQ_VCR_ENABLE);
- pStep->setWriteSignalDev(0x74);
+ pStep->setWriteSignalDev(0x64);
pStep->setEqVCRModeDev(0x1F);
if (addStep(STEP_ID_VCR_ENABLE_CMD_REPLY, pStep) != 0) {
delete pStep;
@@ -493,7 +493,7 @@
// eq mode change
CEqModeChangeStep* pStep = new CEqModeChangeStep();
pStep->setName(STEP_EQ_MODE_CHANGE);
- pStep->setWriteSignalDev(0x75);
+ pStep->setWriteSignalDev(0x65);
pStep->setEqModeDev(0x1E);
if (addStep(STEP_ID_EQMODE_CHANGE_CMD_REPLY, pStep) != 0) {
delete pStep;
diff --git a/SourceCode/Bond/Servo/CPageGraph1.cpp b/SourceCode/Bond/Servo/CPageGraph1.cpp
index f274ae0..b9c2555 100644
--- a/SourceCode/Bond/Servo/CPageGraph1.cpp
+++ b/SourceCode/Bond/Servo/CPageGraph1.cpp
@@ -83,6 +83,12 @@
BOOL bAlive = pEquipment->isAlive();
if (EQ_ID_EFEM == nID) {
DeviceStatus status = bAlive ? DeviceStatus::ONLINE : DeviceStatus::OFFLINE;
+ UpdateDeviceStatus(INDICATE_FLIPER, status);
+ UpdateDeviceStatus(INDICATE_ALIGNER, status);
+ UpdateDeviceStatus(INDICATE_LPORT1, status);
+ UpdateDeviceStatus(INDICATE_LPORT2, status);
+ UpdateDeviceStatus(INDICATE_LPORT3, status);
+ UpdateDeviceStatus(INDICATE_LPORT4, status);
UpdateDeviceStatus(INDICATE_ROBOT_ARM1, status);
UpdateDeviceStatus(INDICATE_ROBOT_ARM2, status);
}
diff --git a/SourceCode/Bond/Servo/GridControl/CellRange.h b/SourceCode/Bond/Servo/GridControl/CellRange.h
new file mode 100644
index 0000000..5fd2004
--- /dev/null
+++ b/SourceCode/Bond/Servo/GridControl/CellRange.h
@@ -0,0 +1,156 @@
+///////////////////////////////////////////////////////////////////////
+// CellRange.h: header file
+//
+// MFC Grid Control - interface for the CCellRange class.
+//
+// Written by Chris Maunder <cmaunder@mail.com>
+// Copyright (c) 1998-2002. All Rights Reserved.
+//
+// This code may be used in compiled form in any way you desire. This
+// file may be redistributed unmodified by any means PROVIDING it is
+// not sold for profit without the authors written consent, and
+// providing that this notice and the authors name and all copyright
+// notices remains intact.
+//
+// An email letting me know how you are using it would be nice as well.
+//
+// This file is provided "as is" with no expressed or implied warranty.
+// The author accepts no liability for any damage/loss of business that
+// this product may cause.
+//
+// For use with CGridCtrl v2.20+
+//
+//////////////////////////////////////////////////////////////////////
+
+#if !defined(AFX_CELLRANGE_H__F86EF761_725A_11D1_ABBA_00A0243D1382__INCLUDED_)
+#define AFX_CELLRANGE_H__F86EF761_725A_11D1_ABBA_00A0243D1382__INCLUDED_
+
+#if _MSC_VER >= 1000
+#pragma once
+#endif // _MSC_VER >= 1000
+
+// The code contained in this file is based on the original
+// WorldCom Grid control written by Joe Willcoxson,
+// mailto:chinajoe@aol.com
+// http://users.aol.com/chinajoe
+
+#ifndef max
+#define max(a,b) (((a) > (b)) ? (a) : (b))
+#endif
+
+#ifndef min
+#define min(a,b) (((a) < (b)) ? (a) : (b))
+#endif
+
+class CCellID
+{
+// Attributes
+public:
+ int row, col;
+
+// Operations
+public:
+ explicit CCellID(int nRow = -1, int nCol = -1) : row(nRow), col(nCol) {}
+
+ int IsValid() const { return (row >= 0 && col >= 0); }
+ int operator==(const CCellID& rhs) const { return (row == rhs.row && col == rhs.col); }
+ int operator!=(const CCellID& rhs) const { return !operator==(rhs); }
+};
+
+class CCellRange
+{
+public:
+
+ CCellRange(int nMinRow = -1, int nMinCol = -1, int nMaxRow = -1, int nMaxCol = -1)
+ {
+ Set(nMinRow, nMinCol, nMaxRow, nMaxCol);
+ }
+
+ void Set(int nMinRow = -1, int nMinCol = -1, int nMaxRow = -1, int nMaxCol = -1);
+
+ int IsValid() const;
+ int InRange(int row, int col) const;
+ int InRange(const CCellID& cellID) const;
+ int Count() { return (m_nMaxRow - m_nMinRow + 1) * (m_nMaxCol - m_nMinCol + 1); }
+
+ CCellID GetTopLeft() const;
+ CCellRange Intersect(const CCellRange& rhs) const;
+
+ int GetMinRow() const {return m_nMinRow;}
+ void SetMinRow(int minRow) {m_nMinRow = minRow;}
+
+ int GetMinCol() const {return m_nMinCol;}
+ void SetMinCol(int minCol) {m_nMinCol = minCol;}
+
+ int GetMaxRow() const {return m_nMaxRow;}
+ void SetMaxRow(int maxRow) {m_nMaxRow = maxRow;}
+
+ int GetMaxCol() const {return m_nMaxCol;}
+ void SetMaxCol(int maxCol) {m_nMaxCol = maxCol;}
+
+ int GetRowSpan() const {return m_nMaxRow - m_nMinRow + 1;}
+ int GetColSpan() const {return m_nMaxCol - m_nMinCol + 1;}
+
+ void operator=(const CCellRange& rhs);
+ int operator==(const CCellRange& rhs);
+ int operator!=(const CCellRange& rhs);
+
+protected:
+ int m_nMinRow;
+ int m_nMinCol;
+ int m_nMaxRow;
+ int m_nMaxCol;
+};
+
+inline void CCellRange::Set(int minRow, int minCol, int maxRow, int maxCol)
+{
+ m_nMinRow = minRow;
+ m_nMinCol = minCol;
+ m_nMaxRow = maxRow;
+ m_nMaxCol = maxCol;
+}
+
+inline void CCellRange::operator=(const CCellRange& rhs)
+{
+ if (this != &rhs) Set(rhs.m_nMinRow, rhs.m_nMinCol, rhs.m_nMaxRow, rhs.m_nMaxCol);
+}
+
+inline int CCellRange::operator==(const CCellRange& rhs)
+{
+ return ((m_nMinRow == rhs.m_nMinRow) && (m_nMinCol == rhs.m_nMinCol) &&
+ (m_nMaxRow == rhs.m_nMaxRow) && (m_nMaxCol == rhs.m_nMaxCol));
+}
+
+inline int CCellRange::operator!=(const CCellRange& rhs)
+{
+ return !operator==(rhs);
+}
+
+inline int CCellRange::IsValid() const
+{
+ return (m_nMinRow >= 0 && m_nMinCol >= 0 && m_nMaxRow >= 0 && m_nMaxCol >= 0 &&
+ m_nMinRow <= m_nMaxRow && m_nMinCol <= m_nMaxCol);
+}
+
+inline int CCellRange::InRange(int row, int col) const
+{
+ return (row >= m_nMinRow && row <= m_nMaxRow && col >= m_nMinCol && col <= m_nMaxCol);
+}
+
+inline int CCellRange::InRange(const CCellID& cellID) const
+{
+ return InRange(cellID.row, cellID.col);
+}
+
+inline CCellID CCellRange::GetTopLeft() const
+{
+ return CCellID(m_nMinRow, m_nMinCol);
+}
+
+inline CCellRange CCellRange::Intersect(const CCellRange& rhs) const
+{
+ return CCellRange(max(m_nMinRow,rhs.m_nMinRow), max(m_nMinCol,rhs.m_nMinCol),
+ min(m_nMaxRow,rhs.m_nMaxRow), min(m_nMaxCol,rhs.m_nMaxCol));
+}
+
+#endif // !defined(AFX_CELLRANGE_H__F86EF761_725A_11D1_ABBA_00A0243D1382__INCLUDED_)
diff --git a/SourceCode/Bond/Servo/GridControl/GridCell.cpp b/SourceCode/Bond/Servo/GridControl/GridCell.cpp
new file mode 100644
index 0000000..370413c
--- /dev/null
+++ b/SourceCode/Bond/Servo/GridControl/GridCell.cpp
@@ -0,0 +1,294 @@
+// GridCell.cpp : implementation file
+//
+// MFC Grid Control - Main grid cell class
+//
+// Provides the implementation for the "default" cell type of the
+// grid control. Adds in cell editing.
+//
+// Written by Chris Maunder <chris@codeproject.com>
+// Copyright (c) 1998-2005. All Rights Reserved.
+//
+// This code may be used in compiled form in any way you desire. This
+// file may be redistributed unmodified by any means PROVIDING it is
+// not sold for profit without the authors written consent, and
+// providing that this notice and the authors name and all copyright
+// notices remains intact.
+//
+// An email letting me know how you are using it would be nice as well.
+//
+// This file is provided "as is" with no expressed or implied warranty.
+// The author accepts no liability for any damage/loss of business that
+// this product may cause.
+//
+// For use with CGridCtrl v2.20+
+//
+// History:
+// Eric Woodruff - 20 Feb 2000 - Added PrintCell() plus other minor changes
+// Ken Bertelson - 12 Apr 2000 - Split CGridCell into CGridCell and CGridCellBase
+// <kenbertelson@hotmail.com>
+// C Maunder - 17 Jun 2000 - Font handling optimsed, Added CGridDefaultCell
+//
+/////////////////////////////////////////////////////////////////////////////
+
+#include "stdafx.h"
+#include "GridCell.h"
+#include "GridCtrl.h"
+#include "GridInPlaceEdit.h"
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#undef THIS_FILE
+static const char* THIS_FILE = __FILE__;
+#endif
+
+IMPLEMENT_DYNCREATE(CGridCell, CGridCellBase)
+IMPLEMENT_DYNCREATE(CGridDefaultCell, CGridCell)
+
+/////////////////////////////////////////////////////////////////////////////
+// GridCell
+
+CGridCell::CGridCell()
+{
+ m_plfFont = NULL;
+ CGridCell::Reset();
+}
+
+CGridCell::~CGridCell()
+{
+ if (m_plfFont)
+ {
+ delete m_plfFont;
+ m_plfFont = NULL;
+ }
+
+
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// GridCell Attributes
+
+void CGridCell::operator=(const CGridCell& cell)
+{
+ if (this != &cell) CGridCellBase::operator=(cell);
+}
+
+void CGridCell::Reset()
+{
+ CGridCellBase::Reset();
+
+ m_strText.Empty();
+ m_nImage = -1;
+ m_lParam = NULL; // BUG FIX J. Bloggs 20/10/03
+ m_pGrid = NULL;
+ m_bEditing = FALSE;
+ m_pEditWnd = NULL;
+
+ m_nFormat = (DWORD)-1; // Use default from CGridDefaultCell
+ m_crBkClr = CLR_DEFAULT; // Background colour (or CLR_DEFAULT)
+ m_crFgClr = CLR_DEFAULT; // Forground colour (or CLR_DEFAULT)
+ m_nMargin = (UINT)-1; // Use default from CGridDefaultCell
+
+ if (m_plfFont)
+ {
+ delete m_plfFont;
+ m_plfFont = NULL;
+ }
+ m_plfFont = NULL; // Cell font
+}
+
+void CGridCell::SetFont(const LOGFONT* plf)
+{
+ if (plf == NULL)
+ {
+ if (m_plfFont)
+ {
+ delete m_plfFont;
+ m_plfFont = NULL;
+ }
+ }
+ else
+ {
+ if (!m_plfFont)
+ m_plfFont = new LOGFONT;
+ if (m_plfFont)
+ memcpy(m_plfFont, plf, sizeof(LOGFONT));
+ }
+}
+
+LOGFONT* CGridCell::GetFont() const
+{
+ if (m_plfFont == NULL)
+ {
+ CGridDefaultCell *pDefaultCell = (CGridDefaultCell*) GetDefaultCell();
+ if (!pDefaultCell)
+ return NULL;
+
+ return pDefaultCell->GetFont();
+ }
+
+ return m_plfFont;
+}
+
+CFont* CGridCell::GetFontObject() const
+{
+ // If the default font is specified, use the default cell implementation
+ if (m_plfFont == NULL)
+ {
+ CGridDefaultCell *pDefaultCell = (CGridDefaultCell*) GetDefaultCell();
+ if (!pDefaultCell)
+ return NULL;
+
+ return pDefaultCell->GetFontObject();
+ }
+ else
+ {
+ static CFont Font;
+ Font.DeleteObject();
+ Font.CreateFontIndirect(m_plfFont);
+ return &Font;
+ }
+}
+
+DWORD CGridCell::GetFormat() const
+{
+ if (m_nFormat == (DWORD)-1)
+ {
+ CGridDefaultCell *pDefaultCell = (CGridDefaultCell*) GetDefaultCell();
+ if (!pDefaultCell)
+ return 0;
+
+ return pDefaultCell->GetFormat();
+ }
+
+ return m_nFormat;
+}
+
+UINT CGridCell::GetMargin() const
+{
+ if (m_nMargin == (UINT)-1)
+ {
+ CGridDefaultCell *pDefaultCell = (CGridDefaultCell*) GetDefaultCell();
+ if (!pDefaultCell)
+ return 0;
+
+ return pDefaultCell->GetMargin();
+ }
+
+ return m_nMargin;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// GridCell Operations
+
+BOOL CGridCell::Edit(int nRow, int nCol, CRect rect, CPoint /* point */, UINT nID, UINT nChar)
+{
+ if ( m_bEditing )
+ {
+ if (m_pEditWnd)
+ m_pEditWnd->SendMessage ( WM_CHAR, nChar );
+ }
+ else
+ {
+ DWORD dwStyle = ES_LEFT;
+ if (GetFormat() & DT_RIGHT)
+ dwStyle = ES_RIGHT;
+ else if (GetFormat() & DT_CENTER)
+ dwStyle = ES_CENTER;
+
+ m_bEditing = TRUE;
+
+ // InPlaceEdit auto-deletes itself
+ CGridCtrl* pGrid = GetGrid();
+ m_pEditWnd = new CGridInPlaceEdit(pGrid, rect, dwStyle, nID, nRow, nCol, GetText(), nChar);
+ }
+ return TRUE;
+}
+
+void CGridCell::EndEdit()
+{
+ if (m_pEditWnd)
+ ((CGridInPlaceEdit*)m_pEditWnd)->EndEdit();
+}
+
+void CGridCell::OnEndEdit()
+{
+ m_bEditing = FALSE;
+ m_pEditWnd = NULL;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// CGridDefaultCell
+
+CGridDefaultCell::CGridDefaultCell()
+{
+#ifdef _WIN32_WCE
+ m_nFormat = DT_LEFT|DT_VCENTER|DT_SINGLELINE|DT_NOPREFIX;
+#else
+ m_nFormat = DT_CENTER|DT_VCENTER|DT_SINGLELINE|DT_NOPREFIX | DT_END_ELLIPSIS;
+#endif
+ m_crFgClr = CLR_DEFAULT;
+ m_crBkClr = CLR_DEFAULT;
+ m_Size = CSize(30,10);
+ m_dwStyle = 0;
+
+#ifdef _WIN32_WCE
+ LOGFONT lf;
+ GetObject(GetStockObject(SYSTEM_FONT), sizeof(LOGFONT), &lf);
+ SetFont(&lf);
+#else // not CE
+ NONCLIENTMETRICS ncm;
+ memset(&ncm,0,sizeof(NONCLIENTMETRICS));
+ ncm.cbSize = sizeof(NONCLIENTMETRICS);
+ //VERIFY(SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICS), &ncm, 0));
+ SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICS), &ncm, 0);
+ SetFont(&(ncm.lfMessageFont));
+#endif
+}
+
+CGridDefaultCell::~CGridDefaultCell()
+{
+ m_Font.DeleteObject();
+}
+
+void CGridDefaultCell::SetFont(const LOGFONT* plf)
+{
+// ASSERT(plf);
+
+ if (!plf) return;
+
+ m_Font.DeleteObject();
+ m_Font.CreateFontIndirect(plf);
+
+ CGridCell::SetFont(plf);
+
+ // Get the font size and hence the default cell size
+ CDC* pDC = CDC::FromHandle(::GetDC(NULL));
+ if (pDC)
+ {
+ CFont* pOldFont = pDC->SelectObject(&m_Font);
+
+ SetMargin(pDC->GetTextExtent(_T(" "), 1).cx);
+ m_Size = pDC->GetTextExtent(_T(" XXXXXXXXXXXX "), 14);
+ m_Size.cy = (m_Size.cy * 3) / 2;
+
+ pDC->SelectObject(pOldFont);
+ ReleaseDC(NULL, pDC->GetSafeHdc());
+ }
+ else
+ {
+ SetMargin(3);
+ m_Size = CSize(40,16);
+ }
+}
+
+LOGFONT* CGridDefaultCell::GetFont() const
+{
+// ASSERT(m_plfFont); // This is the default - it CAN'T be NULL!
+ return m_plfFont;
+}
+
+CFont* CGridDefaultCell::GetFontObject() const
+{
+// ASSERT(m_Font.GetSafeHandle());
+ return (CFont*) &m_Font;
+}
diff --git a/SourceCode/Bond/Servo/GridControl/GridCell.h b/SourceCode/Bond/Servo/GridControl/GridCell.h
new file mode 100644
index 0000000..11664fd
--- /dev/null
+++ b/SourceCode/Bond/Servo/GridControl/GridCell.h
@@ -0,0 +1,143 @@
+/////////////////////////////////////////////////////////////////////////////
+// GridCell.h : header file
+//
+// MFC Grid Control - Grid cell class header file
+//
+// Written by Chris Maunder <chris@codeproject.com>
+// Copyright (c) 1998-2005. All Rights Reserved.
+//
+// This code may be used in compiled form in any way you desire. This
+// file may be redistributed unmodified by any means PROVIDING it is
+// not sold for profit without the authors written consent, and
+// providing that this notice and the authors name and all copyright
+// notices remains intact.
+//
+// An email letting me know how you are using it would be nice as well.
+//
+// This file is provided "as is" with no expressed or implied warranty.
+// The author accepts no liability for any damage/loss of business that
+// this product may cause.
+//
+// For use with CGridCtrl v2.20+
+//
+//////////////////////////////////////////////////////////////////////
+
+#if !defined(AFX_GRIDCELL_H__519FA702_722C_11D1_ABBA_00A0243D1382__INCLUDED_)
+#define AFX_GRIDCELL_H__519FA702_722C_11D1_ABBA_00A0243D1382__INCLUDED_
+
+#if _MSC_VER >= 1000
+#pragma once
+#endif // _MSC_VER >= 1000
+
+class CGridCtrl;
+#include "GridCellBase.h"
+
+// Each cell contains one of these. Fields "row" and "column" are not stored since we
+// will usually have acces to them in other ways, and they are an extra 8 bytes per
+// cell that is probably unnecessary.
+
+class CGridCell : public CGridCellBase
+{
+ friend class CGridCtrl;
+ DECLARE_DYNCREATE(CGridCell)
+
+// Construction/Destruction
+public:
+ CGridCell();
+ virtual ~CGridCell();
+
+// Attributes
+public:
+ void operator=(const CGridCell& cell);
+
+ virtual void SetText(LPCTSTR szText) { m_strText = szText; }
+ virtual void SetImage(int nImage) { m_nImage = nImage; }
+ virtual void SetData(LPARAM lParam) { m_lParam = lParam; }
+ virtual void SetGrid(CGridCtrl* pGrid) { m_pGrid = pGrid; }
+ // virtual void SetState(const DWORD nState); - use base class version
+ virtual void SetFormat(DWORD nFormat) { m_nFormat = nFormat; }
+ virtual void SetTextClr(COLORREF clr) { m_crFgClr = clr; }
+ virtual void SetBackClr(COLORREF clr) { m_crBkClr = clr; }
+ virtual void SetFont(const LOGFONT* plf);
+ virtual void SetMargin(UINT nMargin) { m_nMargin = nMargin; }
+ virtual CWnd* GetEditWnd() const { return m_pEditWnd; }
+ virtual void SetCoords(int /*nRow*/, int /*nCol*/) {} // don't need to know the row and
+ // column for base implementation
+
+ virtual LPCTSTR GetText() const { return (m_strText.IsEmpty())? _T("") : LPCTSTR(m_strText); }
+ virtual int GetImage() const { return m_nImage; }
+ virtual LPARAM GetData() const { return m_lParam; }
+ virtual CGridCtrl* GetGrid() const { return m_pGrid; }
+ // virtual DWORD GetState() const - use base class
+ virtual DWORD GetFormat() const;
+ virtual COLORREF GetTextClr() const { return m_crFgClr; } // TODO: change to use default cell
+ virtual COLORREF GetBackClr() const { return m_crBkClr; }
+ virtual LOGFONT* GetFont() const;
+ virtual CFont* GetFontObject() const;
+ virtual UINT GetMargin() const;
+
+ virtual BOOL IsEditing() const { return m_bEditing; }
+ virtual BOOL IsDefaultFont() const { return (m_plfFont == NULL); }
+ virtual void Reset();
+
+// editing cells
+public:
+ virtual BOOL Edit(int nRow, int nCol, CRect rect, CPoint point, UINT nID, UINT nChar);
+ virtual void EndEdit();
+protected:
+ virtual void OnEndEdit();
+
+protected:
+ CString m_strText; // Cell text (or binary data if you wish...)
+ LPARAM m_lParam; // 32-bit value to associate with item
+ int m_nImage; // Index of the list view item抯 icon
+ DWORD m_nFormat;
+ COLORREF m_crFgClr;
+ COLORREF m_crBkClr;
+ LOGFONT* m_plfFont;
+ UINT m_nMargin;
+
+ BOOL m_bEditing; // Cell being edited?
+
+ CGridCtrl* m_pGrid; // Parent grid control
+ CWnd* m_pEditWnd;
+};
+
+// This class is for storing grid default values. It's a little heavy weight, so
+// don't use it in bulk
+class CGridDefaultCell : public CGridCell
+{
+ DECLARE_DYNCREATE(CGridDefaultCell)
+
+// Construction/Destruction
+public:
+ CGridDefaultCell();
+ virtual ~CGridDefaultCell();
+
+public:
+ virtual DWORD GetStyle() const { return m_dwStyle; }
+ virtual void SetStyle(DWORD dwStyle) { m_dwStyle = dwStyle; }
+ virtual int GetWidth() const { return m_Size.cx; }
+ virtual int GetHeight() const { return m_Size.cy; }
+ virtual void SetWidth(int nWidth) { m_Size.cx = nWidth; }
+ virtual void SetHeight(int nHeight) { m_Size.cy = nHeight; }
+
+ // Disable these properties
+ virtual void SetData(LPARAM /*lParam*/) { ASSERT(FALSE); }
+ virtual void SetState(DWORD /*nState*/) { ASSERT(FALSE); }
+ virtual DWORD GetState() const { return CGridCell::GetState()|GVIS_READONLY; }
+ virtual void SetCoords( int /*row*/, int /*col*/) { /*ASSERT(FALSE);*/ }
+ virtual void SetFont(const LOGFONT* /*plf*/);
+ virtual LOGFONT* GetFont() const;
+ virtual CFont* GetFontObject() const;
+
+protected:
+ CSize m_Size; // Default Size
+ CFont m_Font; // Cached font
+ DWORD m_dwStyle; // Cell Style - unused
+};
+
+//{{AFX_INSERT_LOCATION}}
+// Microsoft Developer Studio will insert additional declarations immediately before the previous line.
+
+#endif // !defined(AFX_GRIDCELL_H__519FA702_722C_11D1_ABBA_00A0243D1382__INCLUDED_)
diff --git a/SourceCode/Bond/Servo/GridControl/GridCellBase.cpp b/SourceCode/Bond/Servo/GridControl/GridCellBase.cpp
new file mode 100644
index 0000000..4b426fd
--- /dev/null
+++ b/SourceCode/Bond/Servo/GridControl/GridCellBase.cpp
@@ -0,0 +1,773 @@
+// GridCellBase.cpp : implementation file
+//
+// MFC Grid Control - Main grid cell base class
+//
+// Provides the implementation for the base cell type of the
+// grid control. No data is stored (except for state) but default
+// implementations of drawing, printingetc provided. MUST be derived
+// from to be used.
+//
+// Written by Chris Maunder <chris@codeproject.com>
+// Copyright (c) 1998-2005. All Rights Reserved.
+//
+// This code may be used in compiled form in any way you desire. This
+// file may be redistributed unmodified by any means PROVIDING it is
+// not sold for profit without the authors written consent, and
+// providing that this notice and the authors name and all copyright
+// notices remains intact.
+//
+// An email letting me know how you are using it would be nice as well.
+//
+// This file is provided "as is" with no expressed or implied warranty.
+// The author accepts no liability for any damage/loss of business that
+// this product may cause.
+//
+// For use with CGridCtrl v2.22+
+//
+// History:
+// Ken Bertelson - 12 Apr 2000 - Split CGridCell into CGridCell and CGridCellBase
+// C Maunder - 19 May 2000 - Fixed sort arrow drawing (Ivan Ilinov)
+// C Maunder - 29 Aug 2000 - operator= checks for NULL font before setting (Martin Richter)
+// C Maunder - 15 Oct 2000 - GetTextExtent fixed (Martin Richter)
+// C Maunder - 1 Jan 2001 - Added ValidateEdit
+// Yogurt - 13 Mar 2004 - GetCellExtent fixed
+//
+// NOTES: Each grid cell should take care of it's own drawing, though the Draw()
+// method takes an "erase background" paramter that is called if the grid
+// decides to draw the entire grid background in on hit. Certain ambient
+// properties such as the default font to use, and hints on how to draw
+// fixed cells should be fetched from the parent grid. The grid trusts the
+// cells will behave in a certain way, and the cells trust the grid will
+// supply accurate information.
+//
+/////////////////////////////////////////////////////////////////////////////
+
+#include "stdafx.h"
+#include "GridCtrl.h"
+#include "GridCellBase.h"
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#undef THIS_FILE
+static const char* THIS_FILE = __FILE__;
+#endif
+
+IMPLEMENT_DYNAMIC(CGridCellBase, CObject)
+
+/////////////////////////////////////////////////////////////////////////////
+// GridCellBase
+
+CGridCellBase::CGridCellBase()
+{
+ Reset();
+}
+
+CGridCellBase::~CGridCellBase()
+{
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// GridCellBase Operations
+
+void CGridCellBase::Reset()
+{
+ m_nState = 0;
+}
+
+void CGridCellBase::operator=(const CGridCellBase& cell)
+{
+ if (this == &cell) return;
+
+ SetGrid(cell.GetGrid()); // do first in case of dependencies
+
+ SetText(cell.GetText());
+ SetImage(cell.GetImage());
+ SetData(cell.GetData());
+ SetState(cell.GetState());
+ SetFormat(cell.GetFormat());
+ SetTextClr(cell.GetTextClr());
+ SetBackClr(cell.GetBackClr());
+ SetFont(cell.IsDefaultFont()? NULL : cell.GetFont());
+ SetMargin(cell.GetMargin());
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// CGridCellBase Attributes
+
+// Returns a pointer to a cell that holds default values for this particular type of cell
+CGridCellBase* CGridCellBase::GetDefaultCell() const
+{
+ if (GetGrid())
+ return GetGrid()->GetDefaultCell(IsFixedRow(), IsFixedCol());
+ return NULL;
+}
+
+
+/////////////////////////////////////////////////////////////////////////////
+// CGridCellBase Operations
+
+// EFW - Various changes to make it draw cells better when using alternate
+// color schemes. Also removed printing references as that's now done
+// by PrintCell() and fixed the sort marker so that it doesn't draw out
+// of bounds.
+BOOL CGridCellBase::Draw(CDC* pDC, int nRow, int nCol, CRect rect, BOOL bEraseBkgnd /*=TRUE*/)
+{
+ // Note - all through this function we totally brutalise 'rect'. Do not
+ // depend on it's value being that which was passed in.
+
+ CGridCtrl* pGrid = GetGrid();
+// ASSERT(pGrid);
+
+ if (!pGrid || !pDC)
+ return FALSE;
+
+ if( rect.Width() <= 0 || rect.Height() <= 0) // prevents imagelist item from drawing even
+ return FALSE; // though cell is hidden
+
+ //TRACE3("Drawing %scell %d, %d\n", IsFixed()? _T("Fixed ") : _T(""), nRow, nCol);
+
+ int nSavedDC = pDC->SaveDC();
+ pDC->SetBkMode(TRANSPARENT);
+
+ // Get the default cell implementation for this kind of cell. We use it if this cell
+ // has anything marked as "default"
+ CGridDefaultCell *pDefaultCell = (CGridDefaultCell*) GetDefaultCell();
+ if (!pDefaultCell)
+ return FALSE;
+
+ // Set up text and background colours
+ COLORREF TextClr, TextBkClr;
+
+ TextClr = (GetTextClr() == CLR_DEFAULT)? pDefaultCell->GetTextClr() : GetTextClr();
+ if (GetBackClr() == CLR_DEFAULT)
+ TextBkClr = pDefaultCell->GetBackClr();
+ else
+ {
+ bEraseBkgnd = TRUE;
+ TextBkClr = GetBackClr();
+ }
+
+ // Draw cell background and highlighting (if necessary)
+ if ( IsFocused() || IsDropHighlighted() )
+ {
+ // Always draw even in list mode so that we can tell where the
+ // cursor is at. Use the highlight colors though.
+ if(GetState() & GVIS_SELECTED)
+ {
+ TextBkClr = ::GetSysColor(COLOR_HIGHLIGHT);
+ TextClr = ::GetSysColor(COLOR_HIGHLIGHTTEXT);
+ bEraseBkgnd = TRUE;
+ }
+
+ rect.right++; rect.bottom++; // FillRect doesn't draw RHS or bottom
+ if (bEraseBkgnd)
+ {
+ TRY
+ {
+ CBrush brush(TextBkClr);
+ pDC->FillRect(rect, &brush);
+ }
+ CATCH(CResourceException, e)
+ {
+ //e->ReportError();
+ }
+ END_CATCH
+ }
+
+ // Don't adjust frame rect if no grid lines so that the
+ // whole cell is enclosed.
+ if(pGrid->GetGridLines() != GVL_NONE)
+ {
+ rect.right--;
+ rect.bottom--;
+ }
+
+ if (pGrid->GetFrameFocusCell())
+ {
+ // Use same color as text to outline the cell so that it shows
+ // up if the background is black.
+ TRY
+ {
+ CBrush brush(TextClr);
+ pDC->FrameRect(rect, &brush);
+ }
+ CATCH(CResourceException, e)
+ {
+ //e->ReportError();
+ }
+ END_CATCH
+ }
+ pDC->SetTextColor(TextClr);
+
+ // Adjust rect after frame draw if no grid lines
+ if(pGrid->GetGridLines() == GVL_NONE)
+ {
+ rect.right--;
+ rect.bottom--;
+ }
+
+ //rect.DeflateRect(0,1,1,1); - Removed by Yogurt
+ }
+ else if ((GetState() & GVIS_SELECTED))
+ {
+ rect.right++; rect.bottom++; // FillRect doesn't draw RHS or bottom
+ pDC->FillSolidRect(rect, ::GetSysColor(COLOR_HIGHLIGHT));
+ rect.right--; rect.bottom--;
+ pDC->SetTextColor(::GetSysColor(COLOR_HIGHLIGHTTEXT));
+ }
+ else
+ {
+ if (bEraseBkgnd)
+ {
+ rect.right++; rect.bottom++; // FillRect doesn't draw RHS or bottom
+ CBrush brush(TextBkClr);
+ pDC->FillRect(rect, &brush);
+ rect.right--; rect.bottom--;
+ }
+ pDC->SetTextColor(TextClr);
+ }
+
+ // Draw lines only when wanted
+ if (IsFixed() && pGrid->GetGridLines() != GVL_NONE)
+ {
+ CCellID FocusCell = pGrid->GetFocusCell();
+
+ // As above, always show current location even in list mode so
+ // that we know where the cursor is at.
+ BOOL bHiliteFixed = pGrid->GetTrackFocusCell() && pGrid->IsValid(FocusCell) &&
+ (FocusCell.row == nRow || FocusCell.col == nCol);
+
+ // If this fixed cell is on the same row/col as the focus cell,
+ // highlight it.
+ if (bHiliteFixed)
+ {
+ rect.right++; rect.bottom++;
+ pDC->DrawEdge(rect, BDR_SUNKENINNER /*EDGE_RAISED*/, BF_RECT);
+ rect.DeflateRect(1,1);
+ }
+ else
+ {
+ CPen lightpen(PS_SOLID, 1, ::GetSysColor(COLOR_3DHIGHLIGHT)),
+ darkpen(PS_SOLID, 1, ::GetSysColor(COLOR_3DDKSHADOW)),
+ *pOldPen = pDC->GetCurrentPen();
+
+ pDC->SelectObject(&lightpen);
+ pDC->MoveTo(rect.right, rect.top);
+ pDC->LineTo(rect.left, rect.top);
+ pDC->LineTo(rect.left, rect.bottom);
+
+ pDC->SelectObject(&darkpen);
+ pDC->MoveTo(rect.right, rect.top);
+ pDC->LineTo(rect.right, rect.bottom);
+ pDC->LineTo(rect.left, rect.bottom);
+
+ pDC->SelectObject(pOldPen);
+ rect.DeflateRect(1,1);
+ }
+ }
+
+ // Draw Text and image
+#if !defined(_WIN32_WCE_NO_PRINTING) && !defined(GRIDCONTROL_NO_PRINTING)
+ if (!pDC->m_bPrinting)
+#endif
+ {
+ CFont *pFont = GetFontObject();
+// ASSERT(pFont);
+ if (pFont)
+ pDC->SelectObject(pFont);
+ }
+
+ //rect.DeflateRect(GetMargin(), 0); - changed by Yogurt
+ rect.DeflateRect(GetMargin(), GetMargin());
+ rect.right++;
+ rect.bottom++;
+
+ if (pGrid->GetImageList() && GetImage() >= 0)
+ {
+ IMAGEINFO Info;
+ if (pGrid->GetImageList()->GetImageInfo(GetImage(), &Info))
+ {
+ // would like to use a clipping region but seems to have issue
+ // working with CMemDC directly. Instead, don't display image
+ // if any part of it cut-off
+ //
+ // CRgn rgn;
+ // rgn.CreateRectRgnIndirect(rect);
+ // pDC->SelectClipRgn(&rgn);
+ // rgn.DeleteObject();
+
+ /*
+ // removed by Yogurt
+ int nImageWidth = Info.rcImage.right-Info.rcImage.left+1;
+ int nImageHeight = Info.rcImage.bottom-Info.rcImage.top+1;
+ if( nImageWidth + rect.left <= rect.right + (int)(2*GetMargin())
+ && nImageHeight + rect.top <= rect.bottom + (int)(2*GetMargin()) )
+ {
+ pGrid->GetImageList()->Draw(pDC, GetImage(), rect.TopLeft(), ILD_NORMAL);
+ }
+ */
+ // Added by Yogurt
+ int nImageWidth = Info.rcImage.right-Info.rcImage.left;
+ int nImageHeight = Info.rcImage.bottom-Info.rcImage.top;
+ if ((nImageWidth + rect.left <= rect.right) && (nImageHeight + rect.top <= rect.bottom))
+ pGrid->GetImageList()->Draw(pDC, GetImage(), rect.TopLeft(), ILD_NORMAL);
+
+ //rect.left += nImageWidth+GetMargin();
+ }
+ }
+
+ // Draw sort arrow
+ if (pGrid->GetSortColumn() == nCol && nRow == 0)
+ {
+ CSize size = pDC->GetTextExtent(_T("M"));
+ int nOffset = 2;
+
+ // Base the size of the triangle on the smaller of the column
+ // height or text height with a slight offset top and bottom.
+ // Otherwise, it can get drawn outside the bounds of the cell.
+ size.cy -= (nOffset * 2);
+
+ if (size.cy >= rect.Height())
+ size.cy = rect.Height() - (nOffset * 2);
+
+ size.cx = size.cy; // Make the dimensions square
+
+ // Kludge for vertical text
+ BOOL bVertical = (GetFont()->lfEscapement == 900);
+
+ // Only draw if it'll fit!
+ //if (size.cx + rect.left < rect.right + (int)(2*GetMargin())) - changed / Yogurt
+ if (size.cx + rect.left < rect.right)
+ {
+ int nTriangleBase = rect.bottom - nOffset - size.cy; // Triangle bottom right
+ //int nTriangleBase = (rect.top + rect.bottom - size.cy)/2; // Triangle middle right
+ //int nTriangleBase = rect.top + nOffset; // Triangle top right
+
+ //int nTriangleLeft = rect.right - size.cx; // Triangle RHS
+ //int nTriangleLeft = (rect.right + rect.left - size.cx)/2; // Triangle middle
+ //int nTriangleLeft = rect.left; // Triangle LHS
+
+ int nTriangleLeft;
+ if (bVertical)
+ nTriangleLeft = (rect.right + rect.left - size.cx)/2; // Triangle middle
+ else
+ nTriangleLeft = rect.right - size.cx; // Triangle RHS
+
+ CPen penShadow(PS_SOLID, 0, ::GetSysColor(COLOR_3DSHADOW));
+ CPen penLight(PS_SOLID, 0, ::GetSysColor(COLOR_3DHILIGHT));
+ if (pGrid->GetSortAscending())
+ {
+ // Draw triangle pointing upwards
+ CPen *pOldPen = (CPen*) pDC->SelectObject(&penLight);
+ pDC->MoveTo( nTriangleLeft + 1, nTriangleBase + size.cy + 1);
+ pDC->LineTo( nTriangleLeft + (size.cx / 2) + 1, nTriangleBase + 1 );
+ pDC->LineTo( nTriangleLeft + size.cx + 1, nTriangleBase + size.cy + 1);
+ pDC->LineTo( nTriangleLeft + 1, nTriangleBase + size.cy + 1);
+
+ pDC->SelectObject(&penShadow);
+ pDC->MoveTo( nTriangleLeft, nTriangleBase + size.cy );
+ pDC->LineTo( nTriangleLeft + (size.cx / 2), nTriangleBase );
+ pDC->LineTo( nTriangleLeft + size.cx, nTriangleBase + size.cy );
+ pDC->LineTo( nTriangleLeft, nTriangleBase + size.cy );
+ pDC->SelectObject(pOldPen);
+ }
+ else
+ {
+ // Draw triangle pointing downwards
+ CPen *pOldPen = (CPen*) pDC->SelectObject(&penLight);
+ pDC->MoveTo( nTriangleLeft + 1, nTriangleBase + 1 );
+ pDC->LineTo( nTriangleLeft + (size.cx / 2) + 1, nTriangleBase + size.cy + 1 );
+ pDC->LineTo( nTriangleLeft + size.cx + 1, nTriangleBase + 1 );
+ pDC->LineTo( nTriangleLeft + 1, nTriangleBase + 1 );
+
+ pDC->SelectObject(&penShadow);
+ pDC->MoveTo( nTriangleLeft, nTriangleBase );
+ pDC->LineTo( nTriangleLeft + (size.cx / 2), nTriangleBase + size.cy );
+ pDC->LineTo( nTriangleLeft + size.cx, nTriangleBase );
+ pDC->LineTo( nTriangleLeft, nTriangleBase );
+ pDC->SelectObject(pOldPen);
+ }
+
+ if (!bVertical)
+ rect.right -= size.cy;
+ }
+ }
+
+ // We want to see '&' characters so use DT_NOPREFIX
+ GetTextRect(rect);
+ rect.right++;
+ rect.bottom++;
+
+ DrawText(pDC->m_hDC, GetText(), -1, rect, GetFormat() | DT_NOPREFIX);
+
+ pDC->RestoreDC(nSavedDC);
+
+ return TRUE;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// CGridCellBase Mouse and Cursor events
+
+// Not yet implemented
+void CGridCellBase::OnMouseEnter()
+{
+// TRACE0("Mouse entered cell\n");
+}
+
+void CGridCellBase::OnMouseOver()
+{
+ //TRACE0("Mouse over cell\n");
+}
+
+// Not Yet Implemented
+void CGridCellBase::OnMouseLeave()
+{
+// TRACE0("Mouse left cell\n");
+}
+
+void CGridCellBase::OnClick( CPoint PointCellRelative)
+{
+ UNUSED_ALWAYS(PointCellRelative);
+// TRACE2("Mouse Left btn up in cell at x=%i y=%i\n", PointCellRelative.x, PointCellRelative.y);
+}
+
+void CGridCellBase::OnClickDown( CPoint PointCellRelative)
+{
+ UNUSED_ALWAYS(PointCellRelative);
+ // TRACE2("Mouse Left btn down in cell at x=%i y=%i\n", PointCellRelative.x, PointCellRelative.y);
+}
+
+void CGridCellBase::OnRClick( CPoint PointCellRelative)
+{
+ UNUSED_ALWAYS(PointCellRelative);
+ // TRACE2("Mouse right-clicked in cell at x=%i y=%i\n", PointCellRelative.x, PointCellRelative.y);
+}
+
+void CGridCellBase::OnDblClick( CPoint PointCellRelative)
+{
+ UNUSED_ALWAYS(PointCellRelative);
+// TRACE2("Mouse double-clicked in cell at x=%i y=%i\n", PointCellRelative.x, PointCellRelative.y);
+}
+
+// Return TRUE if you set the cursor
+BOOL CGridCellBase::OnSetCursor()
+{
+#ifndef _WIN32_WCE_NO_CURSOR
+ SetCursor(AfxGetApp()->LoadStandardCursor(IDC_ARROW));
+#endif
+ return TRUE;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// CGridCellBase editing
+
+void CGridCellBase::OnEndEdit()
+{
+// ASSERT( FALSE);
+}
+
+BOOL CGridCellBase::ValidateEdit(LPCTSTR str)
+{
+ UNUSED_ALWAYS(str);
+ return TRUE;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// CGridCellBase Sizing
+
+BOOL CGridCellBase::GetTextRect( LPRECT pRect) // i/o: i=dims of cell rect; o=dims of text rect
+{
+ if (GetImage() >= 0)
+ {
+ IMAGEINFO Info;
+
+ CGridCtrl* pGrid = GetGrid();
+ CImageList* pImageList = pGrid->GetImageList();
+
+ if (pImageList && pImageList->GetImageInfo( GetImage(), &Info))
+ {
+ int nImageWidth = Info.rcImage.right-Info.rcImage.left+1;
+ pRect->left += nImageWidth + GetMargin();
+ }
+ }
+
+ return TRUE;
+}
+
+// By default this uses the selected font (which is a bigger font)
+CSize CGridCellBase::GetTextExtent(LPCTSTR szText, CDC* pDC /*= NULL*/)
+{
+ CGridCtrl* pGrid = GetGrid();
+// ASSERT(pGrid);
+
+ BOOL bReleaseDC = FALSE;
+ if (pDC == NULL || szText == NULL)
+ {
+ if (szText)
+ pDC = pGrid->GetDC();
+ if (pDC == NULL || szText == NULL)
+ {
+ CGridDefaultCell* pDefCell = (CGridDefaultCell*) GetDefaultCell();
+// ASSERT(pDefCell);
+ return CSize(pDefCell->GetWidth(), pDefCell->GetHeight());
+ }
+ bReleaseDC = TRUE;
+ }
+
+ CFont *pOldFont = NULL,
+ *pFont = GetFontObject();
+ if (pFont)
+ pOldFont = pDC->SelectObject(pFont);
+
+ CSize size;
+ int nFormat = GetFormat();
+
+ // If the cell is a multiline cell, then use the width of the cell
+ // to get the height
+ if ((nFormat & DT_WORDBREAK) && !(nFormat & DT_SINGLELINE))
+ {
+ CString str = szText;
+ int nMaxWidth = 0;
+ while (TRUE)
+ {
+ int nPos = str.Find(_T('\n'));
+ CString TempStr = (nPos < 0)? str : str.Left(nPos);
+ int nTempWidth = pDC->GetTextExtent(TempStr).cx;
+ if (nTempWidth > nMaxWidth)
+ nMaxWidth = nTempWidth;
+
+ if (nPos < 0)
+ break;
+ str = str.Mid(nPos + 1); // Bug fix by Thomas Steinborn
+ }
+
+ CRect rect;
+ rect.SetRect(0,0, nMaxWidth+1, 0);
+ pDC->DrawText(szText, -1, rect, nFormat | DT_CALCRECT);
+ size = rect.Size();
+ }
+ else
+ size = pDC->GetTextExtent(szText, (int)_tcslen(szText));
+
+ // Removed by Yogurt
+ //TEXTMETRIC tm;
+ //pDC->GetTextMetrics(&tm);
+ //size.cx += (tm.tmOverhang);
+
+ if (pOldFont)
+ pDC->SelectObject(pOldFont);
+
+ size += CSize(2*GetMargin(), 2*GetMargin());
+
+ // Kludge for vertical text
+ LOGFONT *pLF = GetFont();
+ if (pLF->lfEscapement == 900 || pLF->lfEscapement == -900)
+ {
+ int nTemp = size.cx;
+ size.cx = size.cy;
+ size.cy = nTemp;
+ size += CSize(0, 4*GetMargin());
+ }
+
+ if (bReleaseDC)
+ pGrid->ReleaseDC(pDC);
+
+ return size;
+}
+
+
+CSize CGridCellBase::GetCellExtent(CDC* pDC)
+{
+ CSize size = GetTextExtent(GetText(), pDC);
+ CSize ImageSize(0,0);
+
+ int nImage = GetImage();
+ if (nImage >= 0)
+ {
+ CGridCtrl* pGrid = GetGrid();
+// ASSERT(pGrid);
+ IMAGEINFO Info;
+ if (pGrid->GetImageList() && pGrid->GetImageList()->GetImageInfo(nImage, &Info))
+ {
+ ImageSize = CSize(Info.rcImage.right-Info.rcImage.left,
+ Info.rcImage.bottom-Info.rcImage.top);
+ if (size.cx > 2*(int)GetMargin ())
+ ImageSize.cx += GetMargin();
+ ImageSize.cy += 2*(int)GetMargin ();
+ }
+ }
+ size.cx += ImageSize.cx + 1;
+ size.cy = max(size.cy, ImageSize.cy) + 1;
+ if (IsFixed())
+ {
+ size.cx++;
+ size.cy++;
+ }
+ return size;
+}
+
+// EFW - Added to print cells so that grids that use different colors are
+// printed correctly.
+BOOL CGridCellBase::PrintCell(CDC* pDC, int /*nRow*/, int /*nCol*/, CRect rect)
+{
+#if defined(_WIN32_WCE_NO_PRINTING) || defined(GRIDCONTROL_NO_PRINTING)
+ return FALSE;
+#else
+ COLORREF crFG, crBG;
+ GV_ITEM Item;
+
+ CGridCtrl* pGrid = GetGrid();
+ if (!pGrid || !pDC)
+ return FALSE;
+
+ if( rect.Width() <= 0
+ || rect.Height() <= 0) // prevents imagelist item from drawing even
+ return FALSE; // though cell is hidden
+
+ int nSavedDC = pDC->SaveDC();
+
+ pDC->SetBkMode(TRANSPARENT);
+
+ if (pGrid->GetShadedPrintOut())
+ {
+ // Get the default cell implementation for this kind of cell. We use it if this cell
+ // has anything marked as "default"
+ CGridDefaultCell *pDefaultCell = (CGridDefaultCell*) GetDefaultCell();
+ if (!pDefaultCell)
+ return FALSE;
+
+ // Use custom color if it doesn't match the default color and the
+ // default grid background color. If not, leave it alone.
+ if(IsFixed())
+ crBG = (GetBackClr() != CLR_DEFAULT) ? GetBackClr() : pDefaultCell->GetBackClr();
+ else
+ crBG = (GetBackClr() != CLR_DEFAULT && GetBackClr() != pDefaultCell->GetBackClr()) ?
+ GetBackClr() : CLR_DEFAULT;
+
+ // Use custom color if the background is different or if it doesn't
+ // match the default color and the default grid text color.
+ if(IsFixed())
+ crFG = (GetBackClr() != CLR_DEFAULT) ? GetTextClr() : pDefaultCell->GetTextClr();
+ else
+ crFG = (GetBackClr() != CLR_DEFAULT) ? GetTextClr() : pDefaultCell->GetTextClr();
+
+ // If not printing on a color printer, adjust the foreground color
+ // to a gray scale if the background color isn't used so that all
+ // colors will be visible. If not, some colors turn to solid black
+ // or white when printed and may not show up. This may be caused by
+ // coarse dithering by the printer driver too (see image note below).
+ if(pDC->GetDeviceCaps(NUMCOLORS) == 2 && crBG == CLR_DEFAULT)
+ crFG = RGB(GetRValue(crFG) * 0.30, GetGValue(crFG) * 0.59,
+ GetBValue(crFG) * 0.11);
+
+ // Only erase the background if the color is not the default
+ // grid background color.
+ if(crBG != CLR_DEFAULT)
+ {
+ CBrush brush(crBG);
+ rect.right++; rect.bottom++;
+ pDC->FillRect(rect, &brush);
+ rect.right--; rect.bottom--;
+ }
+ }
+ else
+ {
+ crBG = CLR_DEFAULT;
+ crFG = RGB(0, 0, 0);
+ }
+
+ pDC->SetTextColor(crFG);
+
+ CFont *pFont = GetFontObject();
+ if (pFont)
+ pDC->SelectObject(pFont);
+
+ /*
+ // ***************************************************
+ // Disabled - if you need this functionality then you'll need to rewrite.
+ // Create the appropriate font and select into DC.
+ CFont Font;
+ // Bold the fixed cells if not shading the print out. Use italic
+ // font it it is enabled.
+ const LOGFONT* plfFont = GetFont();
+ if(IsFixed() && !pGrid->GetShadedPrintOut())
+ {
+ Font.CreateFont(plfFont->lfHeight, 0, 0, 0, FW_BOLD, plfFont->lfItalic, 0, 0,
+ ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
+#ifndef _WIN32_WCE
+ PROOF_QUALITY,
+#else
+ DEFAULT_QUALITY,
+#endif
+ VARIABLE_PITCH | FF_SWISS, plfFont->lfFaceName);
+ }
+ else
+ Font.CreateFontIndirect(plfFont);
+
+ pDC->SelectObject(&Font);
+ // ***************************************************
+ */
+
+ // Draw lines only when wanted on fixed cells. Normal cell grid lines
+ // are handled in OnPrint.
+ if(pGrid->GetGridLines() != GVL_NONE && IsFixed())
+ {
+ CPen lightpen(PS_SOLID, 1, ::GetSysColor(COLOR_3DHIGHLIGHT)),
+ darkpen(PS_SOLID, 1, ::GetSysColor(COLOR_3DDKSHADOW)),
+ *pOldPen = pDC->GetCurrentPen();
+
+ pDC->SelectObject(&lightpen);
+ pDC->MoveTo(rect.right, rect.top);
+ pDC->LineTo(rect.left, rect.top);
+ pDC->LineTo(rect.left, rect.bottom);
+
+ pDC->SelectObject(&darkpen);
+ pDC->MoveTo(rect.right, rect.top);
+ pDC->LineTo(rect.right, rect.bottom);
+ pDC->LineTo(rect.left, rect.bottom);
+
+ rect.DeflateRect(1,1);
+ pDC->SelectObject(pOldPen);
+ }
+
+ rect.DeflateRect(GetMargin(), 0);
+
+ if(pGrid->GetImageList() && GetImage() >= 0)
+ {
+ // NOTE: If your printed images look like fuzzy garbage, check the
+ // settings on your printer driver. If it's using coarse
+ // dithering and/or vector graphics, they may print wrong.
+ // Changing to fine dithering and raster graphics makes them
+ // print properly. My HP 4L had that problem.
+
+ IMAGEINFO Info;
+ if(pGrid->GetImageList()->GetImageInfo(GetImage(), &Info))
+ {
+ int nImageWidth = Info.rcImage.right-Info.rcImage.left;
+ pGrid->GetImageList()->Draw(pDC, GetImage(), rect.TopLeft(), ILD_NORMAL);
+ rect.left += nImageWidth+GetMargin();
+ }
+ }
+
+ // Draw without clipping so as not to lose text when printed for real
+ // DT_NOCLIP removed 01.01.01. Slower, but who cares - we are printing!
+ DrawText(pDC->m_hDC, GetText(), -1, rect,
+ GetFormat() | /*DT_NOCLIP | */ DT_NOPREFIX);
+
+ pDC->RestoreDC(nSavedDC);
+
+ return TRUE;
+#endif
+}
+
+/*****************************************************************************
+Callable by derived classes, only
+*****************************************************************************/
+LRESULT CGridCellBase::SendMessageToParent(int nRow, int nCol, int nMessage)
+{
+ CGridCtrl* pGrid = GetGrid();
+ if( pGrid)
+ return pGrid->SendMessageToParent(nRow, nCol, nMessage);
+ else
+ return 0;
+}
\ No newline at end of file
diff --git a/SourceCode/Bond/Servo/GridControl/GridCellBase.h b/SourceCode/Bond/Servo/GridControl/GridCellBase.h
new file mode 100644
index 0000000..d038c82
--- /dev/null
+++ b/SourceCode/Bond/Servo/GridControl/GridCellBase.h
@@ -0,0 +1,172 @@
+/////////////////////////////////////////////////////////////////////////////
+// GridCellBase.h : header file
+//
+// MFC Grid Control - Grid cell base class header file
+//
+// Written by Chris Maunder <chris@codeproject.com>
+// Copyright (c) 1998-2005. All Rights Reserved.
+//
+// This code may be used in compiled form in any way you desire. This
+// file may be redistributed unmodified by any means PROVIDING it is
+// not sold for profit without the authors written consent, and
+// providing that this notice and the authors name and all copyright
+// notices remains intact.
+//
+// An email letting me know how you are using it would be nice as well.
+//
+// This file is provided "as is" with no expressed or implied warranty.
+// The author accepts no liability for any damage/loss of business that
+// this product may cause.
+//
+// For use with CGridCtrl v2.22+
+//
+//////////////////////////////////////////////////////////////////////
+
+#if !defined(AFX_GRIDCELLBASE_H__519FA702_722C_11D1_ABBA_00A0243D1382__INCLUDED_)
+#define AFX_GRIDCELLBASE_H__519FA702_722C_11D1_ABBA_00A0243D1382__INCLUDED_
+
+#if _MSC_VER >= 1000
+#pragma once
+#endif // _MSC_VER >= 1000
+
+class CGridCtrl;
+
+// Cell states
+#define GVIS_FOCUSED 0x0001
+#define GVIS_SELECTED 0x0002
+#define GVIS_DROPHILITED 0x0004
+#define GVIS_READONLY 0x0008
+#define GVIS_FIXED 0x0010
+#define GVIS_FIXEDROW 0x0020
+#define GVIS_FIXEDCOL 0x0040
+#define GVIS_MODIFIED 0x0080
+
+// Cell data mask
+#define GVIF_TEXT LVIF_TEXT
+#define GVIF_IMAGE LVIF_IMAGE
+#define GVIF_PARAM LVIF_PARAM
+#define GVIF_STATE LVIF_STATE
+#define GVIF_BKCLR (GVIF_STATE<<1)
+#define GVIF_FGCLR (GVIF_STATE<<2)
+#define GVIF_FORMAT (GVIF_STATE<<3)
+#define GVIF_FONT (GVIF_STATE<<4)
+#define GVIF_MARGIN (GVIF_STATE<<5)
+#define GVIF_ALL (GVIF_TEXT|GVIF_IMAGE|GVIF_PARAM|GVIF_STATE|GVIF_BKCLR|GVIF_FGCLR| \
+ GVIF_FORMAT|GVIF_FONT|GVIF_MARGIN)
+
+// Used for Get/SetItem calls.
+typedef struct _GV_ITEM {
+ int row,col; // Row and Column of item
+ UINT mask; // Mask for use in getting/setting cell data
+ UINT nState; // cell state (focus/hilighted etc)
+ DWORD nFormat; // Format of cell
+ int iImage; // index of the list view item抯 icon
+ COLORREF crBkClr; // Background colour (or CLR_DEFAULT)
+ COLORREF crFgClr; // Forground colour (or CLR_DEFAULT)
+ LPARAM lParam; // 32-bit value to associate with item
+ LOGFONT lfFont; // Cell font
+ UINT nMargin; // Internal cell margin
+ CString strText; // Text in cell
+} GV_ITEM;
+
+
+// Each cell contains one of these. Fields "row" and "column" are not stored since we
+// will usually have acces to them in other ways, and they are an extra 8 bytes per
+// cell that is probably unnecessary.
+
+class CGridCellBase : public CObject
+{
+ friend class CGridCtrl;
+ DECLARE_DYNAMIC(CGridCellBase)
+
+// Construction/Destruction
+public:
+ CGridCellBase();
+ virtual ~CGridCellBase();
+
+// Attributes
+public:
+ virtual void SetText(LPCTSTR /* szText */) = 0 ;
+ virtual void SetImage(int /* nImage */) = 0 ;
+ virtual void SetData(LPARAM /* lParam */) = 0 ;
+ virtual void SetState(DWORD nState) { m_nState = nState; }
+ virtual void SetFormat(DWORD /* nFormat */) = 0 ;
+ virtual void SetTextClr(COLORREF /* clr */) = 0 ;
+ virtual void SetBackClr(COLORREF /* clr */) = 0 ;
+ virtual void SetFont(const LOGFONT* /* plf */) = 0 ;
+ virtual void SetMargin( UINT /* nMargin */) = 0 ;
+ virtual void SetGrid(CGridCtrl* /* pGrid */) = 0 ;
+ virtual void SetCoords( int /* nRow */, int /* nCol */) = 0 ;
+
+ virtual LPCTSTR GetText() const = 0 ;
+ virtual LPCTSTR GetTipText() const { return GetText(); } // may override TitleTip return
+ virtual int GetImage() const = 0 ;
+ virtual LPARAM GetData() const = 0 ;
+ virtual DWORD GetState() const { return m_nState; }
+ virtual DWORD GetFormat() const = 0 ;
+ virtual COLORREF GetTextClr() const = 0 ;
+ virtual COLORREF GetBackClr() const = 0 ;
+ virtual LOGFONT * GetFont() const = 0 ;
+ virtual CFont * GetFontObject() const = 0 ;
+ virtual CGridCtrl* GetGrid() const = 0 ;
+ virtual CWnd * GetEditWnd() const = 0 ;
+ virtual UINT GetMargin() const = 0 ;
+
+ virtual CGridCellBase* GetDefaultCell() const;
+
+ virtual BOOL IsDefaultFont() const = 0 ;
+ virtual BOOL IsEditing() const = 0 ;
+ virtual BOOL IsFocused() const { return (m_nState & GVIS_FOCUSED); }
+ virtual BOOL IsFixed() const { return (m_nState & GVIS_FIXED); }
+ virtual BOOL IsFixedCol() const { return (m_nState & GVIS_FIXEDCOL); }
+ virtual BOOL IsFixedRow() const { return (m_nState & GVIS_FIXEDROW); }
+ virtual BOOL IsSelected() const { return (m_nState & GVIS_SELECTED); }
+ virtual BOOL IsReadOnly() const { return (m_nState & GVIS_READONLY); }
+ virtual BOOL IsModified() const { return (m_nState & GVIS_MODIFIED); }
+ virtual BOOL IsDropHighlighted() const { return (m_nState & GVIS_DROPHILITED); }
+
+// Operators
+public:
+ virtual void operator=(const CGridCellBase& cell);
+
+// Operations
+public:
+ virtual void Reset();
+
+ virtual BOOL Draw(CDC* pDC, int nRow, int nCol, CRect rect, BOOL bEraseBkgnd = TRUE);
+ virtual BOOL GetTextRect( LPRECT pRect); // i/o: i=dims of cell rect; o=dims of text rect
+ virtual BOOL GetTipTextRect( LPRECT pRect) { return GetTextRect( pRect); } // may override for btns, etc.
+ virtual CSize GetTextExtent(LPCTSTR str, CDC* pDC = NULL);
+ virtual CSize GetCellExtent(CDC* pDC);
+
+ // Editing
+ virtual BOOL Edit( int /* nRow */, int /* nCol */, CRect /* rect */, CPoint /* point */,
+ UINT /* nID */, UINT /* nChar */) { return FALSE;}
+ virtual BOOL ValidateEdit(LPCTSTR str);
+ virtual void EndEdit() {}
+
+ // EFW - Added to print cells properly
+ virtual BOOL PrintCell(CDC* pDC, int nRow, int nCol, CRect rect);
+
+ // add additional protected grid members required of cells
+ LRESULT SendMessageToParent(int nRow, int nCol, int nMessage);
+
+protected:
+ virtual void OnEndEdit();
+ virtual void OnMouseEnter();
+ virtual void OnMouseOver();
+ virtual void OnMouseLeave();
+ virtual void OnClick( CPoint PointCellRelative);
+ virtual void OnClickDown( CPoint PointCellRelative);
+ virtual void OnRClick( CPoint PointCellRelative);
+ virtual void OnDblClick( CPoint PointCellRelative);
+ virtual BOOL OnSetCursor();
+
+protected:
+ DWORD m_nState; // Cell state (selected/focus etc)
+};
+
+//{{AFX_INSERT_LOCATION}}
+// Microsoft Developer Studio will insert additional declarations immediately before the previous line.
+
+#endif // !defined(AFX_GRIDCELLBASE_H__519FA702_722C_11D1_ABBA_00A0243D1382__INCLUDED_)
diff --git a/SourceCode/Bond/Servo/GridControl/GridCellButton.cpp b/SourceCode/Bond/Servo/GridControl/GridCellButton.cpp
new file mode 100644
index 0000000..f922942
--- /dev/null
+++ b/SourceCode/Bond/Servo/GridControl/GridCellButton.cpp
@@ -0,0 +1,46 @@
+#include "stdafx.h"
+#include "GridCell.h"
+#include "GridCtrl.h"
+#include "GridCellButton.h"
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#undef THIS_FILE
+static const char* THIS_FILE = __FILE__;
+#endif
+
+IMPLEMENT_DYNCREATE(CGridCellButton, CGridCell)
+ CGridCellButton::CGridCellButton(void)
+{
+ m_bPushing = FALSE;
+}
+
+CGridCellButton::~CGridCellButton(void)
+{
+}
+
+BOOL CGridCellButton::Draw(CDC* pDC, int nRow, int nCol, CRect rect, BOOL bEraseBkgnd /* = TRUE */)
+{
+ m_rect = rect;
+ pDC->SetBkMode(TRANSPARENT);
+ rect.DeflateRect(GetMargin(), 0);
+ CFont* pOldFont = pDC->SelectObject(GetFontObject());
+ pDC->DrawFrameControl(rect, DFC_BUTTON, m_bPushing ? DFCS_BUTTONPUSH | DFCS_PUSHED : DFCS_BUTTONPUSH);
+ COLORREF ColorCurrent = pDC->GetTextColor();
+ pDC->SetTextColor(::GetSysColor(COLOR_BTNTEXT));
+ pDC->DrawText(GetText(), -1, rect, DT_CENTER | DT_VCENTER | DT_SINGLELINE | DT_END_ELLIPSIS);
+ pDC->SetTextColor(ColorCurrent);
+ return TRUE;
+}
+
+void CGridCellButton::OnClick(CPoint PointCellRelative)
+{
+ m_bPushing = !m_bPushing;
+ GetGrid()->InvalidateRect(m_rect);
+}
+
+void CGridCellButton::OnMouseLeave()
+{
+ m_bPushing = FALSE;
+ GetGrid()->InvalidateRect(m_rect);
+}
\ No newline at end of file
diff --git a/SourceCode/Bond/Servo/GridControl/GridCellButton.h b/SourceCode/Bond/Servo/GridControl/GridCellButton.h
new file mode 100644
index 0000000..ef4f410
--- /dev/null
+++ b/SourceCode/Bond/Servo/GridControl/GridCellButton.h
@@ -0,0 +1,28 @@
+#ifndef __GRID_CELL_BUTTON__
+#define __GRID_CELL_BUTTON__
+
+#include "GridCell.h"
+
+class CGridCellButton : public CGridCell
+{
+ friend class CGridCtrl;
+ DECLARE_DYNCREATE(CGridCellButton)
+
+public:
+ CGridCellButton(void);
+ virtual ~CGridCellButton(void);
+
+ void SetPushing(BOOL bPush) {m_bPushing = bPush;}
+
+public:
+ virtual BOOL Draw(CDC* pDC, int nRow, int nCol, CRect rect, BOOL bEraseBkgnd = TRUE);
+
+protected:
+ virtual void OnClick(CPoint PointCellRelative);
+ virtual void OnMouseLeave();
+
+protected:
+ CRect m_rect;
+ BOOL m_bPushing;
+};
+#endif
diff --git a/SourceCode/Bond/Servo/GridControl/GridCtrl.cpp b/SourceCode/Bond/Servo/GridControl/GridCtrl.cpp
new file mode 100644
index 0000000..2ad4846
--- /dev/null
+++ b/SourceCode/Bond/Servo/GridControl/GridCtrl.cpp
@@ -0,0 +1,8428 @@
+// GridCtrl.cpp : implementation file
+//
+// MFC Grid Control v2.26
+//
+// Written by Chris Maunder <chris@codeproject.com>
+// Copyright (c) 1998-2005. All Rights Reserved.
+//
+// The code contained in this file was based on the original
+// WorldCom Grid control written by Joe Willcoxson,
+// mailto:chinajoe@aol.com
+// http://users.aol.com/chinajoe
+// (These addresses may be out of date) The code has gone through
+// so many modifications that I'm not sure if there is even a single
+// original line of code. In any case Joe's code was a great
+// framework on which to build.
+//
+// This code may be used in compiled form in any way you desire. This
+// file may be redistributed unmodified by any means PROVIDING it is
+// not sold for profit without the authors written consent, and
+// providing that this notice and the authors name and all copyright
+// notices remains intact.
+//
+// An email letting me know how you are using it would be nice as well.
+//
+// This file is provided "as is" with no expressed or implied warranty.
+// The author accepts no liability for any damage/loss of business that
+// this product may cause.
+//
+// Expect bugs!
+//
+// Please use and enjoy, and let me know of any bugs/mods/improvements
+// that you have found/implemented and I will fix/incorporate them into
+// this file.
+//
+// History:
+// --------
+// This control is constantly evolving, sometimes due to new features that I
+// feel are necessary, and sometimes due to existing bugs. Where possible I
+// have credited the changes to those who contributed code corrections or
+// enhancements (names in brackets) or code suggestions (suggested by...)
+//
+// 1.0 - 1.13 20 Feb 1998 - 6 May 1999
+// First release version. Progressed from being a basic
+// grid based on the original WorldCom Grid control
+// written by Joe Willcoxson (mailto:chinajoe@aol.com,
+// http://users.aol.com/chinajoe) to something a little
+// more feature rich. Rewritten so many times I doubt
+// there is a single line of Joe's code left. Many, many,
+// MANY people sent in bug reports and fixes. Thank you
+// all.
+//
+// 2.0 1 Feb 2000
+// Rewritten to make the grid more object oriented, in
+// that the CGridCell class now takes care of cell-specific
+// tasks. This makes the code more robust, but more
+// importantly it allows the simple insertion of other
+// types of cells.
+//
+// 2.10 11 Mar 2000 - Ken Bertelson and Chris Maunder
+// - Additions for virtual CGridCell support of embedded tree
+// & cell buttons implementation
+// - Optional WYSIWYG printing
+// - Awareness of hidden (0 width/height) rows and columns for
+// key movements, cut, copy, paste, and autosizing
+// - CGridCell can make title tips display any text rather than
+// cell text only
+// - Minor vis bug fixes
+// - CGridCtrl now works with CGridCellBase instead of CGridCell
+// This is a taste of things to come.
+//
+// 2.20 30 Jul 2000 - Chris Maunder
+// - Font storage optimised (suggested by Martin Richter)
+// - AutoSizeColumn works on either column header, data or both
+// - EnsureVisible. The saga continues... (Ken)
+// - Rewrote exception handling
+// - Added TrackFocusCell and FrameFocusCell properties, as well as
+// ExpandLastColumn (suggested by Bruce E. Stemplewski).
+// - InsertColumn now allows you to insert columns at the end of the
+// column range (David Weibel)
+// - Shift-cell-selection more intuitive
+// - API change: Set/GetGridColor now Set/GetGridLineColor
+// - API change: Set/GetBkColor now Set/GetGridBkColor
+// - API change: Set/GetTextColor, Set/GetTextBkColor depricated
+// - API change: Set/GetFixedTextColor, Set/GetFixedBkColor depricated
+// - Stupid DDX_GridControl workaround removed.
+// - Added "virtual mode" via Set/GetVirtualMode
+// - Added SetCallbackFunc to allow callback functions in virtual mode
+// - Added Set/GetAutoSizeStyle
+// - AutoSize() bug fixed
+// - added GVIS_FIXEDROW, GVIS_FIXEDCOL states
+// - added Get/SetFixed[Row|Column]Selection
+// - cell "Get" methods now const'd. Sorry folks...
+// - GetMouseScrollLines now uses win98/W2K friendly code
+// - WS_EX_CLIENTEDGE style now implicit
+//
+// [ Only the latest version and major version changes will be shown ]
+////
+// 2.25 13 Mar 2004 - Chris Maunder
+// - Minor changes so it will compile in VS.NET (inc. Whidbey)
+// - Fixed minor bug in EnsureVisible - Junlin Xu
+// - Changed AfxGetInstanceHandle for AfxGetResourceHandle in RegisterWindowClass
+// - Various changes thanks to Yogurt
+//
+// 2.26 13 Dec 2005 - Pierre Couderc
+// - Added sort in Virtual mode
+// - Change row/column order programatically or via drag and drop
+// - Added save/restore layer (for undoing row/column order changes)
+//
+// TODO: 1) Implement sparse grids (super easy now)
+// 2) Fix it so that as you drag select, the speed of selection increases
+// with time.
+// 3) Scrolling is still a little dodgy (too much grey area). I know there
+// is a simple fix but it's been a low priority
+//
+// ISSUES: 1) WindowFromPoint seems to do weird things in W2K. Causing problems for
+// the rigt-click-on-titletip code.
+//
+/////////////////////////////////////////////////////////////////////////////
+
+#include "stdafx.h"
+#include "GridMemDC.h"
+#include "GridCtrl.h"
+#include <algorithm>
+
+// OLE stuff for clipboard operations
+#include <afxadv.h> // For CSharedFile
+#include <afxconv.h> // For LPTSTR -> LPSTR macros
+
+// OLE stuff for drag and drop
+#include <VersionHelpers.h>
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#undef THIS_FILE
+static const char* THIS_FILE = __FILE__;
+#endif
+
+// Spit out some messages as a sanity check for programmers
+#ifdef GRIDCONTROL_NO_TITLETIPS
+#pragma message(" -- CGridCtrl: No titletips for cells with large data")
+#endif
+#ifdef GRIDCONTROL_NO_DRAGDROP
+#pragma message(" -- CGridCtrl: No OLE drag and drop")
+#endif
+#ifdef GRIDCONTROL_NO_CLIPBOARD
+#pragma message(" -- CGridCtrl: No clipboard support")
+#endif
+#ifdef GRIDCONTROL_NO_PRINTING
+#pragma message(" -- CGridCtrl: No printing support")
+#endif
+
+
+IMPLEMENT_DYNCREATE(CGridCtrl, CWnd)
+
+
+// Get the number of lines to scroll with each mouse wheel notch
+// Why doesn't windows give us this function???
+UINT GetMouseScrollLines()
+{
+ int nScrollLines = 3; // reasonable default
+
+#ifndef _WIN32_WCE
+ // Do things the hard way in win95
+ OSVERSIONINFO VersionInfo = { 0 };
+ VersionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
+ if (!IsWindowsXPOrGreater() || (VersionInfo.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS && VersionInfo.dwMinorVersion == 0))
+ {
+ HKEY hKey;
+ if (RegOpenKeyEx(HKEY_CURRENT_USER, _T("Control Panel\\Desktop"),
+ 0, KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS)
+ {
+ TCHAR szData[128];
+ DWORD dwKeyDataType;
+ DWORD dwDataBufSize = sizeof(szData);
+
+ if (RegQueryValueEx(hKey, _T("WheelScrollLines"), NULL, &dwKeyDataType,
+ (LPBYTE) &szData, &dwDataBufSize) == ERROR_SUCCESS)
+ {
+ nScrollLines = _tcstoul(szData, NULL, 10);
+ }
+ RegCloseKey(hKey);
+ }
+ }
+ // win98 or greater
+ else
+ SystemParametersInfo (SPI_GETWHEELSCROLLLINES, 0, &nScrollLines, 0);
+#endif
+
+ return nScrollLines;
+}
+
+CRect CGridCtrl::rectNull(0, 0, 0, 0);
+CCellID CGridCtrl::cellNull(0, 0);
+/////////////////////////////////////////////////////////////////////////////
+// CGridCtrl
+
+CGridCtrl::CGridCtrl(int nRows, int nCols, int nFixedRows, int nFixedCols)
+{
+ RegisterWindowClass();
+
+#if !defined(GRIDCONTROL_NO_DRAGDROP) || !defined(GRIDCONTROL_NO_CLIPBOARD)
+ _AFX_THREAD_STATE* pState = AfxGetThreadState();
+ if (!pState->m_bNeedTerm && !AfxOleInit())
+ AfxMessageBox(_T("OLE initialization failed. Make sure that the OLE libraries are the correct version"));
+#endif
+
+ // Store the system colours in case they change. The gridctrl uses
+ // these colours, and in OnSysColorChange we can check to see if
+ // the gridctrl colours have been changed from the system colours.
+ // If they have, then leave them, otherwise change them to reflect
+ // the new system colours.
+ m_crWindowText = ::GetSysColor(COLOR_WINDOWTEXT);
+ m_crWindowColour = ::GetSysColor(COLOR_WINDOW);
+ m_cr3DFace = ::GetSysColor(COLOR_3DFACE);
+ m_crShadow = ::GetSysColor(COLOR_3DSHADOW);
+ m_crGridLineColour = RGB(192,192,192);
+
+ m_nRows = 0;
+ m_nCols = 0;
+ m_nFixedRows = 0;
+ m_nFixedCols = 0;
+ m_InDestructor = false;
+
+ m_bVirtualMode = FALSE;
+ m_pfnCallback = NULL;
+
+ m_nVScrollMax = 0; // Scroll position
+ m_nHScrollMax = 0;
+ m_nRowsPerWheelNotch = GetMouseScrollLines(); // Get the number of lines
+ // per mouse wheel notch to scroll
+ m_nBarState = GVL_NONE;
+ m_MouseMode = MOUSE_NOTHING;
+ m_nGridLines = GVL_BOTH;
+ m_bEditable = TRUE;
+ m_bListMode = FALSE;
+ m_bSingleRowSelection = FALSE;
+ m_bSingleColSelection = FALSE;
+ m_bLMouseButtonDown = FALSE;
+ m_bRMouseButtonDown = FALSE;
+ m_bAllowDraw = TRUE; // allow draw updates
+ m_bEnableSelection = TRUE;
+ m_bFixedColumnSelection = TRUE;
+ m_bFixedRowSelection = TRUE;
+ m_bAllowRowResize = TRUE;
+ m_bAllowColumnResize = TRUE;
+ m_bSortOnClick = FALSE; // Sort on header row click
+ m_bHandleTabKey = TRUE;
+#ifdef _WIN32_WCE
+ m_bDoubleBuffer = FALSE; // Use double buffering to avoid flicker?
+#else
+ m_bDoubleBuffer = TRUE; // Use double buffering to avoid flicker?
+#endif
+ m_bTitleTips = TRUE; // show cell title tips
+
+ m_bWysiwygPrinting = FALSE; // use size-to-width printing
+
+ m_bHiddenColUnhide = TRUE; // 0-width columns can be expanded via mouse
+ m_bHiddenRowUnhide = TRUE; // 0-Height rows can be expanded via mouse
+
+ m_bAllowColHide = TRUE; // Columns can be contracted to 0-width via mouse
+ m_bAllowRowHide = TRUE; // Rows can be contracted to 0-height via mouse
+
+ m_bAscending = TRUE; // sorting stuff
+ m_nSortColumn = -1;
+ m_pfnCompare = NULL;
+ m_pfnVirtualCompare = NULL;
+ m_nAutoSizeColumnStyle = GVS_BOTH; // Autosize grid using header and data info
+
+ m_nTimerID = 0; // For drag-selection
+ // LUC
+ m_nTimerInterval = 150; // (in milliseconds)
+ m_nResizeCaptureRange = 3; // When resizing columns/row, the cursor has to be
+ // within +/-3 pixels of the dividing line for
+ // resizing to be possible
+ m_pImageList = NULL; // Images in the grid
+ m_bAllowDragAndDrop = FALSE; // for drag and drop - EFW - off by default
+ m_bTrackFocusCell = FALSE; // Track Focus cell?
+ m_bFrameFocus = TRUE; // Frame the selected cell?
+ m_AllowReorderColumn = false;
+ m_QuitFocusOnTab = false;
+ m_AllowSelectRowInFixedCol = false;
+ m_bDragRowMode = TRUE; // allow to drop a line over another one to change row order
+ m_pRtcDefault = RUNTIME_CLASS(CGridCell);
+
+ SetupDefaultCells();
+ SetGridBkColor(m_crShadow);
+
+ // Set up the initial grid size
+ SetRowCount(nRows);
+ SetColumnCount(nCols);
+ SetFixedRowCount(nFixedRows);
+ SetFixedColumnCount(nFixedCols);
+ // LUC
+ m_nFreezedRows = 0;
+ m_nFreezedCols = 0;
+
+ // LUC
+ m_bExcludeFreezedRowsFromSelection = FALSE;
+ m_bExcludeFreezedColsFromSelection = FALSE;
+
+ SetTitleTipTextClr(CLR_DEFAULT); //FNA
+ SetTitleTipBackClr(CLR_DEFAULT);
+
+ // set initial selection range (ie. none)
+ m_SelectedCellMap.RemoveAll();
+ m_PrevSelectedCellMap.RemoveAll();
+
+#if !defined(_WIN32_WCE_NO_PRINTING) && !defined(GRIDCONTROL_NO_PRINTING)
+ // EFW - Added to support shaded/unshaded printout and
+ // user-definable margins.
+ m_bShadedPrintOut = TRUE;
+ SetPrintMarginInfo(2, 2, 4, 4, 1, 1, 1);
+#endif
+
+ // LUC
+ m_bDrawingMergedCell = FALSE;
+ m_nCurrentMergeID = -1;
+ // LUC
+ m_bShowHorzNonGridArea = FALSE;
+}
+
+CGridCtrl::~CGridCtrl()
+{
+ m_InDestructor = true;
+ DeleteAllItems();
+
+#ifndef GRIDCONTROL_NO_TITLETIPS
+ if (m_bTitleTips && ::IsWindow(m_TitleTip.GetSafeHwnd()))
+ m_TitleTip.DestroyWindow();
+#endif
+
+ DestroyWindow();
+
+#if !defined(GRIDCONTROL_NO_DRAGDROP) || !defined(GRIDCONTROL_NO_CLIPBOARD)
+ // BUG FIX - EFW
+ COleDataSource *pSource = COleDataSource::GetClipboardOwner();
+ if(pSource)
+ COleDataSource::FlushClipboard();
+#endif
+}
+
+// Register the window class if it has not already been registered.
+BOOL CGridCtrl::RegisterWindowClass()
+{
+ WNDCLASS wndcls;
+ //HINSTANCE hInst = AfxGetInstanceHandle();
+ HINSTANCE hInst = AfxGetResourceHandle();
+
+ if (!(::GetClassInfo(hInst, GRIDCTRL_CLASSNAME, &wndcls)))
+ {
+ // otherwise we need to register a new class
+ wndcls.style = CS_DBLCLKS;
+ wndcls.lpfnWndProc = ::DefWindowProc;
+ wndcls.cbClsExtra = wndcls.cbWndExtra = 0;
+ wndcls.hInstance = hInst;
+ wndcls.hIcon = NULL;
+#ifndef _WIN32_WCE_NO_CURSOR
+ wndcls.hCursor = AfxGetApp()->LoadStandardCursor(IDC_ARROW);
+#else
+ wndcls.hCursor = 0;
+#endif
+ wndcls.hbrBackground = (HBRUSH) (COLOR_3DFACE + 1);
+ wndcls.lpszMenuName = NULL;
+ wndcls.lpszClassName = GRIDCTRL_CLASSNAME;
+
+ if (!AfxRegisterClass(&wndcls))
+ {
+ AfxThrowResourceException();
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+BOOL CGridCtrl::Initialise()
+{
+ // Stop re-entry problems
+ static BOOL bInProcedure = FALSE;
+ if (bInProcedure)
+ return FALSE;
+ bInProcedure = TRUE;
+
+#ifndef GRIDCONTROL_NO_TITLETIPS
+ m_TitleTip.SetParentWnd(this);
+#endif
+
+ // This would be a good place to register the droptarget but
+ // unfortunately this causes problems if you are using the
+ // grid in a view.
+ // Moved from OnSize.
+//#ifndef GRIDCONTROL_NO_DRAGDROP
+// m_DropTarget.Register(this);
+//#endif
+
+ if (::IsWindow(m_hWnd))
+ ModifyStyleEx(0, WS_EX_CLIENTEDGE);
+
+ // Kludge: Make sure the client edge shows
+ // This is so horrible it makes my eyes water.
+ CRect rect;
+ GetWindowRect(rect);
+ CWnd* pParent = GetParent();
+ if (pParent != NULL)
+ pParent->ScreenToClient(rect);
+ rect.InflateRect(1,1); MoveWindow(rect);
+ rect.DeflateRect(1,1); MoveWindow(rect);
+
+ bInProcedure = FALSE;
+ return TRUE;
+}
+
+// creates the control - use like any other window create control
+BOOL CGridCtrl::Create(const RECT& rect, CWnd* pParentWnd, UINT nID, DWORD dwStyle)
+{
+// ASSERT(pParentWnd->GetSafeHwnd());
+
+ if (!CWnd::Create(GRIDCTRL_CLASSNAME, NULL, dwStyle, rect, pParentWnd, nID))
+ return FALSE;
+
+ //Initialise(); - called in PreSubclassWnd
+
+ // The number of rows and columns will only be non-zero if the constructor
+ // was called with non-zero initialising parameters. If this window was created
+ // using a dialog template then the number of rows and columns will be 0 (which
+ // means that the code below will not be needed - which is lucky 'cause it ain't
+ // gonna get called in a dialog-template-type-situation.
+
+ TRY
+ {
+ m_arRowHeights.SetSize(m_nRows); // initialize row heights
+ m_arColWidths.SetSize(m_nCols); // initialize column widths
+ }
+ CATCH (CMemoryException, e)
+ {
+ e->ReportError();
+ return FALSE;
+ }
+ END_CATCH
+
+ int i;
+ for (i = 0; i < m_nRows; i++)
+ m_arRowHeights[i] = m_cellDefault.GetHeight();
+ for (i = 0; i < m_nCols; i++)
+ m_arColWidths[i] = m_cellDefault.GetWidth();
+
+ return TRUE;
+}
+
+
+
+
+void CGridCtrl::SetupDefaultCells()
+{
+ m_cellDefault.SetGrid(this); // Normal editable cell
+ m_cellFixedColDef.SetGrid(this); // Cell for fixed columns
+ m_cellFixedRowDef.SetGrid(this); // Cell for fixed rows
+ m_cellFixedRowColDef.SetGrid(this); // Cell for area overlapped by fixed columns/rows
+
+ m_cellDefault.SetTextClr(m_crWindowText);
+ m_cellDefault.SetBackClr(m_crWindowColour);
+ m_cellFixedColDef.SetTextClr(m_crWindowText);
+ m_cellFixedColDef.SetBackClr(m_cr3DFace);
+ m_cellFixedRowDef.SetTextClr(m_crWindowText);
+ m_cellFixedRowDef.SetBackClr(m_cr3DFace);
+ m_cellFixedRowColDef.SetTextClr(m_crWindowText);
+ m_cellFixedRowColDef.SetBackClr(m_cr3DFace);
+}
+
+void CGridCtrl::PreSubclassWindow()
+{
+ CWnd::PreSubclassWindow();
+
+ //HFONT hFont = ::CreateFontIndirect(m_cellDefault.GetFont());
+ //OnSetFont((LPARAM)hFont, 0);
+ //DeleteObject(hFont);
+
+ Initialise();
+}
+
+// Sends a message to the parent in the form of a WM_NOTIFY message with
+// a NM_GRIDVIEW structure attached
+LRESULT CGridCtrl::SendMessageToParent(int nRow, int nCol, int nMessage) const
+{
+ if (!IsWindow(m_hWnd))
+ return 0;
+
+ NM_GRIDVIEW nmgv;
+ nmgv.iRow = nRow;
+ nmgv.iColumn = nCol;
+ nmgv.hdr.hwndFrom = m_hWnd;
+ nmgv.hdr.idFrom = GetDlgCtrlID();
+ nmgv.hdr.code = nMessage;
+
+ CWnd *pOwner = GetOwner();
+ if (pOwner && IsWindow(pOwner->m_hWnd))
+ return pOwner->SendMessage(WM_NOTIFY, nmgv.hdr.idFrom, (LPARAM)&nmgv);
+ else
+ return 0;
+}
+
+// Send a request to the parent to return information on a given cell
+LRESULT CGridCtrl::SendDisplayRequestToParent(GV_DISPINFO* pDisplayInfo) const
+{
+ if (!IsWindow(m_hWnd))
+ return 0;
+
+ // Fix up the message headers
+ pDisplayInfo->hdr.hwndFrom = m_hWnd;
+ pDisplayInfo->hdr.idFrom = GetDlgCtrlID();
+ pDisplayInfo->hdr.code = GVN_GETDISPINFO;
+
+ // Send the message
+ CWnd *pOwner = GetOwner();
+ if (pOwner && IsWindow(pOwner->m_hWnd))
+ return pOwner->SendMessage(WM_NOTIFY, pDisplayInfo->hdr.idFrom, (LPARAM)pDisplayInfo);
+ else
+ return 0;
+}
+
+// Send a hint to the parent about caching information
+LRESULT CGridCtrl::SendCacheHintToParent(const CCellRange& range) const
+{
+ if (!IsWindow(m_hWnd))
+ return 0;
+
+ GV_CACHEHINT CacheHint;
+
+ // Fix up the message headers
+ CacheHint.hdr.hwndFrom = m_hWnd;
+ CacheHint.hdr.idFrom = GetDlgCtrlID();
+ CacheHint.hdr.code = GVN_ODCACHEHINT;
+
+ CacheHint.range = range;
+
+ // Send the message
+ CWnd *pOwner = GetOwner();
+ if (pOwner && IsWindow(pOwner->m_hWnd))
+ return pOwner->SendMessage(WM_NOTIFY, CacheHint.hdr.idFrom, (LPARAM)&CacheHint);
+ else
+ return 0;
+}
+
+#define LAYER_SIGNATURE (0x5FD4E64)
+int CGridCtrl::GetLayer(int** pLayer) // used to save and restore order of columns
+{ // gives back the size of the area (do not forget to delete pLayer)
+ int Length = 2+GetColumnCount()*2;
+ int *Layer = new int[Length]; // the caller is supposed to delete it
+ Layer[0]= LAYER_SIGNATURE;
+ Layer[1]= GetColumnCount();
+ memcpy(&Layer[2], &m_arColOrder[0], GetColumnCount()*sizeof(int));
+ memcpy(&Layer[2+GetColumnCount()], &m_arColWidths[0], GetColumnCount()*sizeof(int));
+ *pLayer = Layer;
+ return Length;
+}
+void CGridCtrl::SetLayer(int* pLayer)
+{ // coming from a previous GetLayer (ignored if not same number of column, or the same revision number)
+ if(pLayer[0] != LAYER_SIGNATURE) return;
+ if(pLayer[1] != GetColumnCount()) return;
+/* TRACE(" %d == %d \n",m_arColOrder[0],pLayer[2]);
+ TRACE(" %d == %d \n",m_arColOrder[1],pLayer[3]);
+ TRACE(" %d == %d \n",m_arColOrder[2],pLayer[4]);
+ TRACE(" %d == %d \n",m_arColWidths[0],pLayer[2+3]);
+ TRACE(" %d == %d \n",m_arColWidths[1],pLayer[3+3]);
+ TRACE(" %d == %d \n",m_arColWidths[2],pLayer[4+3]);
+ TRACE(" %d == %d \n",GetColumnCount(),3);
+
+
+ ASSERT(m_arColOrder[0]==pLayer[2]);
+ ASSERT(m_arColOrder[1]==pLayer[3]);
+ ASSERT(m_arColOrder[2]==pLayer[4]);
+ ASSERT(m_arColWidths[0]==pLayer[2+3]);
+ ASSERT(m_arColWidths[1]==pLayer[3+3]);
+ ASSERT(m_arColWidths[2]==pLayer[4+3]);
+ ASSERT(GetColumnCount()==3);
+*/ memcpy(&m_arColOrder[0],&pLayer[2], GetColumnCount()*sizeof(int));
+ memcpy(&m_arColWidths[0],&pLayer[2+GetColumnCount()], GetColumnCount()*sizeof(int));
+}
+
+BEGIN_MESSAGE_MAP(CGridCtrl, CWnd)
+//EFW - Added ON_WM_RBUTTONUP
+//{{AFX_MSG_MAP(CGridCtrl)
+ ON_WM_PAINT()
+ ON_WM_HSCROLL()
+ ON_WM_VSCROLL()
+ ON_WM_SIZE()
+ ON_WM_LBUTTONUP()
+ ON_WM_LBUTTONDOWN()
+ ON_WM_MOUSEMOVE()
+ ON_WM_TIMER()
+ ON_WM_GETDLGCODE()
+ ON_WM_KEYDOWN()
+ ON_WM_CHAR()
+ ON_WM_LBUTTONDBLCLK()
+ ON_WM_ERASEBKGND()
+ ON_UPDATE_COMMAND_UI(ID_EDIT_SELECT_ALL, OnUpdateEditSelectAll)
+ ON_COMMAND(ID_EDIT_SELECT_ALL, OnEditSelectAll)
+ ON_WM_SYSKEYDOWN()
+//}}AFX_MSG_MAP
+#ifndef _WIN32_WCE_NO_CURSOR
+ ON_WM_SETCURSOR()
+#endif
+#ifndef _WIN32_WCE
+ ON_WM_RBUTTONUP()
+ ON_WM_SYSCOLORCHANGE()
+ ON_WM_CAPTURECHANGED()
+#endif
+#ifndef GRIDCONTROL_NO_CLIPBOARD
+ ON_COMMAND(ID_EDIT_COPY, OnEditCopy)
+ ON_UPDATE_COMMAND_UI(ID_EDIT_COPY, OnUpdateEditCopy)
+ ON_COMMAND(ID_EDIT_CUT, OnEditCut)
+ ON_UPDATE_COMMAND_UI(ID_EDIT_CUT, OnUpdateEditCut)
+ ON_COMMAND(ID_EDIT_PASTE, OnEditPaste)
+ ON_UPDATE_COMMAND_UI(ID_EDIT_PASTE, OnUpdateEditPaste)
+#endif
+#if (_WIN32_WCE >= 210)
+ ON_WM_SETTINGCHANGE()
+#endif
+#if !defined(_WIN32_WCE) && (_MFC_VER >= 0x0421)
+ ON_WM_MOUSEWHEEL()
+#endif
+ ON_MESSAGE(WM_SETFONT, OnSetFont)
+ ON_MESSAGE(WM_GETFONT, OnGetFont)
+ ON_MESSAGE(WM_IME_CHAR, OnImeChar)
+ ON_NOTIFY(GVN_ENDLABELEDIT, IDC_INPLACE_CONTROL, OnEndInPlaceEdit)
+ ON_NOTIFY(GVN_COMBOSELCHANGE, IDC_INPLACE_CONTROL, OnComboSelChange)
+END_MESSAGE_MAP()
+
+
+/////////////////////////////////////////////////////////////////////////////
+// CGridCtrl message handlers
+
+void CGridCtrl::OnPaint()
+{
+ CPaintDC dc(this); // device context for painting
+
+ if (m_bDoubleBuffer) // Use a memory DC to remove flicker
+ {
+ CGridMemDC MemDC(&dc);
+ OnDraw(&MemDC);
+ }
+ else // Draw raw - this helps in debugging vis problems.
+ OnDraw(&dc);
+}
+
+BOOL CGridCtrl::OnEraseBkgnd(CDC* /*pDC*/)
+{
+ return TRUE; // Don't erase the background.
+}
+
+// Custom background erasure. This gets called from within the OnDraw function,
+// since we will (most likely) be using a memory DC to stop flicker. If we just
+// erase the background normally through OnEraseBkgnd, and didn't fill the memDC's
+// selected bitmap with colour, then all sorts of vis problems would occur
+void CGridCtrl::EraseBkgnd(CDC* pDC)
+{
+ CRect VisRect, ClipRect, rect;
+ CBrush FixedRowColBack(GetDefaultCell(TRUE, TRUE)->GetBackClr()),
+ FixedRowBack(GetDefaultCell(TRUE, FALSE)->GetBackClr()),
+ FixedColBack(GetDefaultCell(FALSE, TRUE)->GetBackClr()),
+ TextBack(GetDefaultCell(FALSE, FALSE)->GetBackClr());
+ CBrush Back(GetGridBkColor());
+
+ if (pDC->GetClipBox(ClipRect) == ERROR)
+ return;
+ GetVisibleNonFixedCellRange(VisRect);
+
+ int nFixedColumnWidth = GetFixedColumnWidth();
+ int nFixedRowHeight = GetFixedRowHeight();
+
+ // Draw Fixed row/column background
+ if (ClipRect.left < nFixedColumnWidth && ClipRect.top < nFixedRowHeight)
+ pDC->FillRect(CRect(ClipRect.left, ClipRect.top,
+ nFixedColumnWidth, nFixedRowHeight),
+ &FixedRowColBack);
+
+ // Draw Fixed columns background
+ if (ClipRect.left < nFixedColumnWidth && ClipRect.top < VisRect.bottom)
+ pDC->FillRect(CRect(ClipRect.left, ClipRect.top,
+ nFixedColumnWidth, VisRect.bottom),
+ &FixedColBack);
+
+ // Draw Fixed rows background
+ if (ClipRect.top < nFixedRowHeight &&
+ ClipRect.right > nFixedColumnWidth && ClipRect.left < VisRect.right)
+ pDC->FillRect(CRect(nFixedColumnWidth-1, ClipRect.top,
+ VisRect.right, nFixedRowHeight),
+ &FixedRowBack);
+
+ // Draw non-fixed cell background
+ if (rect.IntersectRect(VisRect, ClipRect))
+ {
+ CRect CellRect(__max(nFixedColumnWidth, rect.left),
+ __max(nFixedRowHeight, rect.top),
+ rect.right, rect.bottom);
+ pDC->FillRect(CellRect, &TextBack);
+ }
+
+ // Draw right hand side of window outside grid
+ if (VisRect.right < ClipRect.right)
+ pDC->FillRect(CRect(VisRect.right, ClipRect.top,
+ ClipRect.right, ClipRect.bottom),
+ &Back);
+
+ // Draw bottom of window below grid
+ if (VisRect.bottom < ClipRect.bottom && ClipRect.left < VisRect.right)
+ pDC->FillRect(CRect(ClipRect.left, VisRect.bottom,
+ VisRect.right, ClipRect.bottom),
+ &Back);
+}
+
+void CGridCtrl::OnSize(UINT nType, int cx, int cy)
+{
+ static BOOL bAlreadyInsideThisProcedure = FALSE;
+ if (bAlreadyInsideThisProcedure)
+ return;
+
+ if (!::IsWindow(m_hWnd))
+ return;
+
+ // This is not the ideal place to register the droptarget
+#ifndef GRIDCONTROL_NO_DRAGDROP
+ m_DropTarget.Register(this);
+#endif
+
+ // Start re-entry blocking
+ bAlreadyInsideThisProcedure = TRUE;
+
+ EndEditing(); // destroy any InPlaceEdit's
+ CWnd::OnSize(nType, cx, cy);
+ ResetScrollBars();
+
+ // End re-entry blocking
+ bAlreadyInsideThisProcedure = FALSE;
+}
+
+UINT CGridCtrl::OnGetDlgCode()
+{
+ UINT nCode = DLGC_WANTARROWS | DLGC_WANTCHARS; // DLGC_WANTALLKEYS; //
+
+ if (m_bHandleTabKey && !IsCTRLpressed())
+ nCode |= DLGC_WANTTAB;
+
+ return nCode;
+}
+
+#ifndef _WIN32_WCE
+// If system colours change, then redo colours
+void CGridCtrl::OnSysColorChange()
+{
+ CWnd::OnSysColorChange();
+
+ if (GetDefaultCell(FALSE, FALSE)->GetTextClr() == m_crWindowText) // Still using system colours
+ GetDefaultCell(FALSE, FALSE)->SetTextClr(::GetSysColor(COLOR_WINDOWTEXT)); // set to new system colour
+ if (GetDefaultCell(FALSE, FALSE)->GetBackClr() == m_crWindowColour)
+ GetDefaultCell(FALSE, FALSE)->SetBackClr(::GetSysColor(COLOR_WINDOW));
+
+ if (GetDefaultCell(TRUE, FALSE)->GetTextClr() == m_crWindowText) // Still using system colours
+ GetDefaultCell(TRUE, FALSE)->SetTextClr(::GetSysColor(COLOR_WINDOWTEXT)); // set to new system colour
+ if (GetDefaultCell(TRUE, FALSE)->GetBackClr() == m_crWindowColour)
+ GetDefaultCell(TRUE, FALSE)->SetBackClr(::GetSysColor(COLOR_WINDOW));
+
+ if (GetDefaultCell(FALSE, TRUE)->GetTextClr() == m_crWindowText) // Still using system colours
+ GetDefaultCell(FALSE, TRUE)->SetTextClr(::GetSysColor(COLOR_WINDOWTEXT)); // set to new system colour
+ if (GetDefaultCell(FALSE, TRUE)->GetBackClr() == m_crWindowColour)
+ GetDefaultCell(FALSE, TRUE)->SetBackClr(::GetSysColor(COLOR_WINDOW));
+
+ if (GetDefaultCell(TRUE, TRUE)->GetTextClr() == m_crWindowText) // Still using system colours
+ GetDefaultCell(TRUE, TRUE)->SetTextClr(::GetSysColor(COLOR_WINDOWTEXT)); // set to new system colour
+ if (GetDefaultCell(TRUE, TRUE)->GetBackClr() == m_crWindowColour)
+ GetDefaultCell(TRUE, TRUE)->SetBackClr(::GetSysColor(COLOR_WINDOW));
+
+ if (GetGridBkColor() == m_crShadow)
+ SetGridBkColor(::GetSysColor(COLOR_3DSHADOW));
+
+ m_crWindowText = ::GetSysColor(COLOR_WINDOWTEXT);
+ m_crWindowColour = ::GetSysColor(COLOR_WINDOW);
+ m_cr3DFace = ::GetSysColor(COLOR_3DFACE);
+ m_crShadow = ::GetSysColor(COLOR_3DSHADOW);
+}
+#endif
+
+#ifndef _WIN32_WCE_NO_CURSOR
+// If we are drag-selecting cells, or drag and dropping, stop now
+void CGridCtrl::OnCaptureChanged(CWnd *pWnd)
+{
+ if (pWnd->GetSafeHwnd() == GetSafeHwnd())
+ return;
+
+ // kill timer if active
+ if (m_nTimerID != 0)
+ {
+ KillTimer(m_nTimerID);
+ m_nTimerID = 0;
+ }
+
+#ifndef GRIDCONTROL_NO_DRAGDROP
+ // Kill drag and drop if active
+ if (m_MouseMode == MOUSE_DRAGGING)
+ m_MouseMode = MOUSE_NOTHING;
+#endif
+}
+#endif
+
+#if (_MFC_VER >= 0x0421) || (_WIN32_WCE >= 210)
+// If system settings change, then redo colours
+void CGridCtrl::OnSettingChange(UINT uFlags, LPCTSTR lpszSection)
+{
+ CWnd::OnSettingChange(uFlags, lpszSection);
+
+ if (GetDefaultCell(FALSE, FALSE)->GetTextClr() == m_crWindowText) // Still using system colours
+ GetDefaultCell(FALSE, FALSE)->SetTextClr(::GetSysColor(COLOR_WINDOWTEXT)); // set to new system colour
+ if (GetDefaultCell(FALSE, FALSE)->GetBackClr() == m_crWindowColour)
+ GetDefaultCell(FALSE, FALSE)->SetBackClr(::GetSysColor(COLOR_WINDOW));
+
+ if (GetDefaultCell(TRUE, FALSE)->GetTextClr() == m_crWindowText) // Still using system colours
+ GetDefaultCell(TRUE, FALSE)->SetTextClr(::GetSysColor(COLOR_WINDOWTEXT)); // set to new system colour
+ if (GetDefaultCell(TRUE, FALSE)->GetBackClr() == m_crWindowColour)
+ GetDefaultCell(TRUE, FALSE)->SetBackClr(::GetSysColor(COLOR_WINDOW));
+
+ if (GetDefaultCell(FALSE, TRUE)->GetTextClr() == m_crWindowText) // Still using system colours
+ GetDefaultCell(FALSE, TRUE)->SetTextClr(::GetSysColor(COLOR_WINDOWTEXT)); // set to new system colour
+ if (GetDefaultCell(FALSE, TRUE)->GetBackClr() == m_crWindowColour)
+ GetDefaultCell(FALSE, TRUE)->SetBackClr(::GetSysColor(COLOR_WINDOW));
+
+ if (GetDefaultCell(TRUE, TRUE)->GetTextClr() == m_crWindowText) // Still using system colours
+ GetDefaultCell(TRUE, TRUE)->SetTextClr(::GetSysColor(COLOR_WINDOWTEXT)); // set to new system colour
+ if (GetDefaultCell(TRUE, TRUE)->GetBackClr() == m_crWindowColour)
+ GetDefaultCell(TRUE, TRUE)->SetBackClr(::GetSysColor(COLOR_WINDOW));
+
+ if (GetGridBkColor() == m_crShadow)
+ SetGridBkColor(::GetSysColor(COLOR_3DSHADOW));
+
+ m_crWindowText = ::GetSysColor(COLOR_WINDOWTEXT);
+ m_crWindowColour = ::GetSysColor(COLOR_WINDOW);
+ m_cr3DFace = ::GetSysColor(COLOR_3DFACE);
+ m_crShadow = ::GetSysColor(COLOR_3DSHADOW);
+
+ m_nRowsPerWheelNotch = GetMouseScrollLines(); // Get the number of lines
+}
+#endif
+
+// For drag-selection. Scrolls hidden cells into view
+// TODO: decrease timer interval over time to speed up selection over time
+void CGridCtrl::OnTimer(UINT_PTR nIDEvent)
+{
+// ASSERT(nIDEvent == WM_LBUTTONDOWN);
+ if (nIDEvent != WM_LBUTTONDOWN)
+ return;
+
+ CPoint pt, origPt;
+
+#ifdef _WIN32_WCE
+ if (m_MouseMode == MOUSE_NOTHING)
+ return;
+ origPt = GetMessagePos();
+#else
+ if (!GetCursorPos(&origPt))
+ return;
+#endif
+
+ ScreenToClient(&origPt);
+
+ CRect rect;
+ GetClientRect(rect);
+
+ // LUC
+ CCellID cell = GetCellFromPt(origPt);
+
+ CCellID idTopLeft = GetTopleftNonFixedCell();
+ if(idTopLeft.row == GetFixedRowCount(TRUE))
+ {
+ m_bExcludeFreezedRowsFromSelection = FALSE;
+ }
+ else if((cell.row > idTopLeft.row) || (m_LeftClickDownCell.row >= idTopLeft.row))
+ {
+ m_bExcludeFreezedRowsFromSelection = TRUE;
+
+ }
+ if(idTopLeft.col == GetFixedColumnCount(TRUE))
+ {
+ m_bExcludeFreezedColsFromSelection = FALSE;
+ }
+ else if((cell.col > idTopLeft.col) || (m_LeftClickDownCell.col >= idTopLeft.col))
+ {
+ m_bExcludeFreezedColsFromSelection = TRUE;
+ }
+
+ int nFixedRowHeight = GetFixedRowHeight(m_bExcludeFreezedRowsFromSelection);
+ int nFixedColWidth = GetFixedColumnWidth(m_bExcludeFreezedColsFromSelection);
+
+ pt = origPt;
+ if (pt.y > rect.bottom)
+ {
+ //SendMessage(WM_VSCROLL, SB_LINEDOWN, 0);
+ SendMessage(WM_KEYDOWN, VK_DOWN, 0);
+
+ if (pt.x < rect.left)
+ pt.x = rect.left;
+ if (pt.x > rect.right)
+ pt.x = rect.right;
+ pt.y = rect.bottom;
+ OnSelecting(GetCellFromPt(pt));
+ }
+ else if (pt.y < nFixedRowHeight)
+ {
+ //SendMessage(WM_VSCROLL, SB_LINEUP, 0);
+ SendMessage(WM_KEYDOWN, VK_UP, 0);
+
+ if (pt.x < rect.left)
+ pt.x = rect.left;
+ if (pt.x > rect.right)
+ pt.x = rect.right;
+ pt.y = nFixedRowHeight + 1;
+ OnSelecting(GetCellFromPt(pt));
+ }
+
+ pt = origPt;
+ if (pt.x > rect.right)
+ {
+ // SendMessage(WM_HSCROLL, SB_LINERIGHT, 0);
+ SendMessage(WM_KEYDOWN, VK_RIGHT, 0);
+
+ if (pt.y < rect.top)
+ pt.y = rect.top;
+ if (pt.y > rect.bottom)
+ pt.y = rect.bottom;
+ pt.x = rect.right;
+ OnSelecting(GetCellFromPt(pt));
+ }
+ else if (pt.x < nFixedColWidth)
+ {
+ //SendMessage(WM_HSCROLL, SB_LINELEFT, 0);
+ SendMessage(WM_KEYDOWN, VK_LEFT, 0);
+
+ if (pt.y < rect.top)
+ pt.y = rect.top;
+ if (pt.y > rect.bottom)
+ pt.y = rect.bottom;
+ pt.x = nFixedColWidth + 1;
+ OnSelecting(GetCellFromPt(pt));
+ }
+
+}
+
+// move about with keyboard
+void CGridCtrl::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
+{
+ if (!IsValid(m_idCurrentCell))
+ {
+ CWnd::OnKeyDown(nChar, nRepCnt, nFlags);
+ return;
+ }
+ CCellID next = m_idCurrentCell;
+ BOOL bChangeLine = FALSE;
+ BOOL bHorzScrollAction = FALSE;
+ BOOL bVertScrollAction = FALSE;
+
+ if (IsCTRLpressed())
+ {
+ switch (nChar)
+ {
+ case 'A':
+ OnEditSelectAll();
+ break;
+ case 'k': // This is ctrl+ on french keyboard, may need to be better processed for other locales
+ AutoSizeColumns();
+ Invalidate();
+ break;
+#ifndef GRIDCONTROL_NO_CLIPBOARD
+ case 'X':
+ OnEditCut();
+ break;
+ case VK_INSERT:
+ case 'C':
+ OnEditCopy();
+ break;
+ case 'V':
+ OnEditPaste();
+ break;
+#endif
+ }
+ }
+
+#ifndef GRIDCONTROL_NO_CLIPBOARD
+ if (IsSHIFTpressed() &&(nChar == VK_INSERT))
+ OnEditPaste();
+#endif
+
+ BOOL bFoundVisible;
+ int iOrig;
+
+ if (nChar == VK_DELETE)
+ {
+ CutSelectedText();
+ }
+ else if (nChar == VK_DOWN)
+ {
+ // don't let user go to a hidden row
+ bFoundVisible = FALSE;
+ iOrig = next.row;
+ next.row++;
+ while( next.row < GetRowCount())
+ {
+ if( GetRowHeight( next.row) > 0)
+ {
+ bFoundVisible = TRUE;
+ break;
+ }
+ next.row++;
+ }
+ if( !bFoundVisible)
+ next.row = iOrig;
+ }
+ else if (nChar == VK_UP)
+ {
+ // don't let user go to a hidden row
+ bFoundVisible = FALSE;
+ iOrig = next.row;
+ next.row--;
+ // LUC
+ //while( next.row >= m_nFixedRows)
+ while( next.row >= GetFixedRowCount(m_bExcludeFreezedRowsFromSelection))
+ {
+ if( GetRowHeight( next.row) > 0)
+ {
+ bFoundVisible = TRUE;
+ break;
+ }
+ next.row--;
+ }
+ if( !bFoundVisible)
+ next.row = iOrig;
+ }
+ else if (nChar == VK_RIGHT || (nChar == VK_TAB && !IsSHIFTpressed()) )
+ {
+ if( (nChar == VK_TAB) && m_QuitFocusOnTab )
+ {
+ CDialog* p= (CDialog*) GetParent();
+ if(p) p->NextDlgCtrl();
+ return;
+
+ }
+ // don't let user go to a hidden column
+ bFoundVisible = FALSE;
+ iOrig = next.col;
+ next.col++;
+
+ if (nChar == VK_TAB)
+ {
+ // If we're at the end of a row, go down a row till we find a non-hidden row
+ if (next.col == (GetColumnCount()) && next.row < (GetRowCount() - 1))
+ {
+ next.row++;
+ while( next.row < GetRowCount())
+ {
+ if( GetRowHeight(next.row) > 0)
+ {
+ bFoundVisible = TRUE;
+ break;
+ }
+ next.row++;
+ }
+
+ // LUC
+ //next.col = m_nFixedCols; // Place focus on first non-fixed column
+ next.col = GetFixedColumnCount(m_bExcludeFreezedColsFromSelection); // Place focus on first non-fixed column
+ bChangeLine = TRUE;
+ }
+ else
+ CWnd::OnKeyDown(nChar, nRepCnt, nFlags);
+ }
+
+ // We're on a non-hidden row, so look across for the next non-hidden column
+ while( next.col < GetColumnCount())
+ {
+ if( GetColumnWidth( next.col) > 0)
+ {
+ bFoundVisible = TRUE;
+ break;
+ }
+ next.col++;
+ }
+
+ // If nothing worked then don't bother
+ if( !bFoundVisible)
+ next.col = iOrig;
+ }
+ else if (nChar == VK_LEFT || (nChar == VK_TAB && IsSHIFTpressed()) )
+ {
+ // don't let user go to a hidden column
+ bFoundVisible = FALSE;
+ iOrig = next.col;
+ next.col--;
+
+ if (nChar == VK_TAB)
+ {
+ // LUC
+ if (next.col == (GetFixedColumnCount(m_bExcludeFreezedColsFromSelection)-1)
+ && next.row > GetFixedRowCount(m_bExcludeFreezedRowsFromSelection))
+ {
+ next.row--;
+ while( next.row > GetFixedRowCount(m_bExcludeFreezedRowsFromSelection))
+ {
+ if( GetRowHeight(next.row) > 0)
+ {
+ bFoundVisible = TRUE;
+ break;
+ }
+ next.row--;
+ }
+
+ next.col = GetColumnCount() - 1;
+ bChangeLine = TRUE;
+ }
+ else
+ CWnd::OnKeyDown(nChar, nRepCnt, nFlags);
+ }
+
+ // LUC
+ //while( next.col >= m_nFixedCols)
+ while(next.col >= GetFixedColumnCount(m_bExcludeFreezedColsFromSelection))
+ {
+ if( GetColumnWidth( next.col) > 0)
+ {
+ bFoundVisible = TRUE;
+ break;
+ }
+ next.col--;
+ }
+ if( !bFoundVisible)
+ next.col = iOrig;
+ }
+ else if (nChar == VK_NEXT)
+ {
+ CCellID idOldTopLeft = GetTopleftNonFixedCell();
+ SendMessage(WM_VSCROLL, SB_PAGEDOWN, 0);
+ bVertScrollAction = TRUE;
+ CCellID idNewTopLeft = GetTopleftNonFixedCell();
+
+ int increment = idNewTopLeft.row - idOldTopLeft.row;
+ if (increment)
+ {
+ next.row += increment;
+ if (next.row >(GetRowCount() - 1))
+ next.row = GetRowCount() - 1;
+ }
+ else
+ next.row = GetRowCount() - 1;
+ }
+ else if (nChar == VK_PRIOR)
+ {
+ CCellID idOldTopLeft = GetTopleftNonFixedCell();
+ SendMessage(WM_VSCROLL, SB_PAGEUP, 0);
+ bVertScrollAction = TRUE;
+ CCellID idNewTopLeft = GetTopleftNonFixedCell();
+
+ int increment = idNewTopLeft.row - idOldTopLeft.row;
+ if (increment)
+ {
+ next.row += increment;
+ // LUC
+ if (next.row < GetFixedRowCount(m_bExcludeFreezedRowsFromSelection))
+ next.row = GetFixedRowCount(m_bExcludeFreezedColsFromSelection);
+ }
+ else
+ // LUC
+ next.row = GetFixedRowCount(m_bExcludeFreezedRowsFromSelection);
+ }
+ else if (nChar == VK_HOME)
+ {
+ // Home and Ctrl-Home work more like Excel
+ // and don't let user go to a hidden cell
+ if (IsCTRLpressed())
+ {
+ SendMessage(WM_VSCROLL, SB_TOP, 0);
+ SendMessage(WM_HSCROLL, SB_LEFT, 0);
+ bVertScrollAction = TRUE;
+ bHorzScrollAction = TRUE;
+ //next.row = m_nFixedRows;
+ //next.col = m_nFixedCols;
+ // LUC
+ next.row = GetFixedRowCount(m_bExcludeFreezedRowsFromSelection);
+ next.col = GetFixedColumnCount(m_bExcludeFreezedColsFromSelection);
+ }
+ else
+ {
+ SendMessage(WM_HSCROLL, SB_LEFT, 0);
+ bHorzScrollAction = TRUE;
+ // LUC
+ //next.col = m_nFixedCols;
+ next.col = GetFixedColumnCount(m_bExcludeFreezedColsFromSelection);
+ }
+ // adjust column to avoid hidden columns and rows
+ while( next.col < GetColumnCount() - 1)
+ {
+ if( GetColumnWidth( next.col) > 0)
+ break;
+ next.col++;
+ }
+ while( next.row < GetRowCount() - 1)
+ {
+ if( GetRowHeight( next.row) > 0)
+ break;
+ next.row++;
+ }
+ }
+ else if (nChar == VK_END)
+ {
+ // End and Ctrl-End work more like Excel
+ // and don't let user go to a hidden cell
+ if (IsCTRLpressed())
+ {
+ SendMessage(WM_VSCROLL, SB_BOTTOM, 0);
+ SendMessage(WM_HSCROLL, SB_RIGHT, 0);
+ bHorzScrollAction = TRUE;
+ bVertScrollAction = TRUE;
+ next.row = GetRowCount() - 1;
+ next.col = GetColumnCount() - 1;
+ }
+ else
+ {
+ SendMessage(WM_HSCROLL, SB_RIGHT, 0);
+ bHorzScrollAction = TRUE;
+ next.col = GetColumnCount() - 1;
+ }
+ // adjust column to avoid hidden columns and rows
+ //while( next.col > m_nFixedCols + 1)
+ while(next.col > GetFixedColumnCount(m_bExcludeFreezedColsFromSelection) + 1)
+ {
+ if( GetColumnWidth( next.col) > 0)
+ break;
+ next.col--;
+ }
+ //while( next.row > m_nFixedRows + 1)
+ while( next.row > GetFixedRowCount(m_bExcludeFreezedRowsFromSelection) + 1)
+ {
+ if( GetRowHeight( next.row) > 0)
+ break;
+ next.row--;
+ }
+ }
+ else if (nChar == VK_F2)
+ {
+ OnEditCell(m_idCurrentCell.row, m_idCurrentCell.col, CPoint( -1, -1), VK_LBUTTON);
+ }
+ else
+ {
+ CWnd::OnKeyDown(nChar, nRepCnt, nFlags);
+ return;
+ }
+
+ if (next != m_idCurrentCell)
+ {
+ // LUC
+
+ int nNextRow = next.row;
+ int nNextCol = next.col;
+
+ int nCurRow = m_idCurrentCell.row;
+ int nCurCol = m_idCurrentCell.col;
+
+ BOOL bMerged = GetTopLeftMergedCell(nCurRow, nCurCol, rectNull);
+
+ switch(nChar)
+ {
+ case VK_LEFT:
+ {
+ if(GetTopLeftMergedCell(nNextRow, nNextCol, rectNull))
+ {
+ next.col = nNextCol;
+ if(bMerged)
+ {
+ // if already in a merged cell make sure the next column is not the leftmost column of the merged cell
+ next.col--;
+ }
+ }
+ break;
+ }
+
+ case VK_RIGHT:
+ {
+ if(GetBottomRightMergedCell(nNextRow, nNextCol, rectNull))
+ {
+ next.col = nNextCol;
+ if(bMerged)
+ {
+ // if already in a merged cell make sure the next column is not the rightmost column of the merged cell
+ next.col++;
+ }
+ }
+ break;
+ }
+
+ case VK_UP:
+ {
+ if(GetTopLeftMergedCell(nNextRow, nNextCol, rectNull))
+ {
+ next.row = nNextRow;
+ if(bMerged)
+ {
+ // if already in a merged cell make sure the next row is not the topmost row of the merged cell
+ next.row--;
+ }
+ }
+ break;
+ }
+
+ case VK_DOWN:
+ {
+ if(GetBottomRightMergedCell(nNextRow, nNextCol, rectNull))
+ {
+ next.row = nNextRow;
+ if(bMerged)
+ {
+ // if already in a merged cell make sure the next row is not the bottommost row of the merged cell
+ next.row++;
+ }
+ }
+ break;
+ }
+ }
+
+ // While moving with the Cursorkeys the current ROW/CELL will get selected
+ // OR Selection will get expanded when SHIFT is pressed
+ // Cut n paste from OnLButtonDown - Franco Bez
+ // Added check for NULL mouse mode - Chris Maunder.
+ if (m_MouseMode == MOUSE_NOTHING)
+ {
+ m_PrevSelectedCellMap.RemoveAll();
+ m_MouseMode = m_bListMode? MOUSE_SELECT_ROW : MOUSE_SELECT_CELLS;
+ if (!IsSHIFTpressed() || nChar == VK_TAB)
+ m_SelectionStartCell = next;
+
+ // Notify parent that selection is changing - Arthur Westerman/Scot Brennecke
+ SendMessageToParent(next.row, next.col, GVN_SELCHANGING);
+ OnSelecting(next);
+ SendMessageToParent(next.row, next.col, GVN_SELCHANGED);
+
+ m_MouseMode = MOUSE_NOTHING;
+ }
+
+ SetFocusCell(next);
+
+ if (!IsCellVisible(next))
+ {
+
+ switch (nChar)
+ {
+ case VK_RIGHT:
+ SendMessage(WM_HSCROLL, SB_LINERIGHT, 0);
+ bHorzScrollAction = TRUE;
+ break;
+
+ case VK_LEFT:
+ SendMessage(WM_HSCROLL, SB_LINELEFT, 0);
+ bHorzScrollAction = TRUE;
+ break;
+
+ case VK_DOWN:
+ SendMessage(WM_VSCROLL, SB_LINEDOWN, 0);
+ bVertScrollAction = TRUE;
+ break;
+
+ case VK_UP:
+ SendMessage(WM_VSCROLL, SB_LINEUP, 0);
+ bVertScrollAction = TRUE;
+ break;
+
+ case VK_TAB:
+ if (IsSHIFTpressed())
+ {
+ if (bChangeLine)
+ {
+ SendMessage(WM_VSCROLL, SB_LINEUP, 0);
+ bVertScrollAction = TRUE;
+ SetScrollPos32(SB_HORZ, m_nHScrollMax);
+ break;
+ }
+ else
+ {
+ SendMessage(WM_HSCROLL, SB_LINELEFT, 0);
+ bHorzScrollAction = TRUE;
+ }
+ }
+ else
+ {
+ if (bChangeLine)
+ {
+ SendMessage(WM_VSCROLL, SB_LINEDOWN, 0);
+ bVertScrollAction = TRUE;
+ SetScrollPos32(SB_HORZ, 0);
+ break;
+ }
+ else
+ {
+ SendMessage(WM_HSCROLL, SB_LINERIGHT, 0);
+ bHorzScrollAction = TRUE;
+ }
+ }
+ break;
+ }
+ EnsureVisible(next); // Make sure cell is visible
+ Invalidate();
+ }
+ EnsureVisible(next); // Make sure cell is visible
+
+ if (bHorzScrollAction)
+ SendMessage(WM_HSCROLL, SB_ENDSCROLL, 0);
+ if (bVertScrollAction)
+ SendMessage(WM_VSCROLL, SB_ENDSCROLL, 0);
+ }
+}
+
+void CGridCtrl::OnKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags)
+{
+ CWnd::OnKeyUp(nChar, nRepCnt, nFlags);
+}
+
+void CGridCtrl::OnSysKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
+{
+#ifdef GRIDCONTROL_USE_TITLETIPS
+ m_TitleTip.Hide(); // hide any titletips
+#endif
+
+ CWnd::OnSysKeyDown(nChar, nRepCnt, nFlags);
+}
+
+// Instant editing of cells when keys are pressed
+void CGridCtrl::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)
+{
+ // EFW - BUG FIX
+ if (!IsCTRLpressed() && m_MouseMode == MOUSE_NOTHING && nChar != VK_ESCAPE)
+ {
+ if (!m_bHandleTabKey || (m_bHandleTabKey && nChar != VK_TAB))
+ OnEditCell(m_idCurrentCell.row, m_idCurrentCell.col, CPoint( -1, -1), nChar);
+ }
+
+ CWnd::OnChar(nChar, nRepCnt, nFlags);
+}
+
+// Added by KiteFly
+LRESULT CGridCtrl::OnImeChar(WPARAM wCharCode, LPARAM)
+{
+ // EFW - BUG FIX
+ if (!IsCTRLpressed() && m_MouseMode == MOUSE_NOTHING && wCharCode != VK_ESCAPE)
+ OnEditCell(m_idCurrentCell.row, m_idCurrentCell.col, CPoint( -1, -1), (UINT)wCharCode);
+ return 0;
+}
+
+// Callback from any CInPlaceEdits that ended. This just calls OnEndEditCell,
+// refreshes the edited cell and moves onto next cell if the return character
+// from the edit says we should.
+void CGridCtrl::OnEndInPlaceEdit(NMHDR* pNMHDR, LRESULT* pResult)
+{
+ GV_DISPINFO *pgvDispInfo = (GV_DISPINFO *)pNMHDR;
+ GV_ITEM *pgvItem = &pgvDispInfo->item;
+
+ // In case OnEndInPlaceEdit called as window is being destroyed
+ if (!IsWindow(GetSafeHwnd()))
+ return;
+
+ OnEndEditCell(pgvItem->row, pgvItem->col, pgvItem->strText);
+ //InvalidateCellRect(CCellID(pgvItem->row, pgvItem->col));
+
+ switch (pgvItem->lParam)
+ {
+ case VK_TAB:
+ case VK_DOWN:
+ case VK_UP:
+ case VK_RIGHT:
+ case VK_LEFT:
+ case VK_NEXT:
+ case VK_PRIOR:
+ case VK_HOME:
+ case VK_END:
+ OnKeyDown((UINT)pgvItem->lParam, 0, 0);
+ OnEditCell(m_idCurrentCell.row, m_idCurrentCell.col, CPoint( -1, -1), (UINT)pgvItem->lParam);
+ }
+
+ *pResult = 0;
+}
+
+
+void CGridCtrl::OnComboSelChange(NMHDR* pNMHDR, LRESULT* pResult)
+{
+ GV_DISPINFO *pgvDispInfo = (GV_DISPINFO *)pNMHDR;
+ GV_ITEM *pgvItem = &pgvDispInfo->item;
+
+ // In case OnEndInPlaceEdit called as window is being destroyed
+ if (!IsWindow(GetSafeHwnd()))
+ return;
+
+ OnEndEditCell(pgvItem->row, pgvItem->col, pgvItem->strText);
+
+ SendMessageToParent(pgvItem->row, pgvItem->col, GVN_COMBOSELCHANGE);
+
+ *pResult = 0;
+}
+
+// Handle horz scrollbar notifications
+void CGridCtrl::OnHScroll(UINT nSBCode, UINT /*nPos*/, CScrollBar* /*pScrollBar*/)
+{
+ EndEditing();
+
+#ifndef GRIDCONTROL_NO_TITLETIPS
+ m_TitleTip.Hide(); // hide any titletips
+#endif
+
+ int scrollPos = GetScrollPos32(SB_HORZ);
+
+ CCellID idTopLeft = GetTopleftNonFixedCell();
+
+ CRect rect;
+ GetClientRect(rect);
+
+ // LUC
+ BOOL bIncludeFreezedCells = FALSE;
+
+ switch (nSBCode)
+ {
+ case SB_LINERIGHT:
+ if (scrollPos < m_nHScrollMax)
+ {
+ // may have contiguous hidden columns. Blow by them
+ while (idTopLeft.col < (GetColumnCount()-1)
+ && GetColumnWidth( idTopLeft.col) < 1 )
+ {
+ idTopLeft.col++;
+ }
+ int xScroll = GetColumnWidth(idTopLeft.col);
+ SetScrollPos32(SB_HORZ, scrollPos + xScroll);
+ if (GetScrollPos32(SB_HORZ) == scrollPos)
+ break; // didn't work
+
+ // LUC
+ rect.left = GetFixedColumnWidth(bIncludeFreezedCells);
+ //rect.left = GetFixedColumnWidth() + xScroll;
+ //ScrollWindow(-xScroll, 0, rect);
+ //rect.left = rect.right - xScroll;
+ InvalidateRect(rect);
+ }
+ break;
+
+ case SB_LINELEFT:
+ if (scrollPos > 0 && idTopLeft.col > GetFixedColumnCount(TRUE))
+ {
+ int iColToUse = idTopLeft.col-1;
+ // may have contiguous hidden columns. Blow by them
+ while( iColToUse > GetFixedColumnCount(TRUE)
+ && GetColumnWidth( iColToUse) < 1 )
+ {
+ iColToUse--;
+ }
+
+ int xScroll = GetColumnWidth(iColToUse);
+ SetScrollPos32(SB_HORZ, __max(0, scrollPos - xScroll));
+ // LUC
+ rect.left = GetFixedColumnWidth(bIncludeFreezedCells);
+ //ScrollWindow(xScroll, 0, rect);
+ //rect.right = rect.left + xScroll;
+ InvalidateRect(rect);
+ }
+ break;
+
+ case SB_PAGERIGHT:
+ if (scrollPos < m_nHScrollMax)
+ {
+ // LUC
+ rect.left = GetFixedColumnWidth(TRUE);
+ int offset = rect.Width();
+ int pos = min(m_nHScrollMax, scrollPos + offset);
+ SetScrollPos32(SB_HORZ, pos);
+ // LUC
+ rect.left = GetFixedColumnWidth(bIncludeFreezedCells);
+ InvalidateRect(rect);
+ }
+ break;
+
+ case SB_PAGELEFT:
+ if (scrollPos > 0)
+ {
+ // LUC
+ rect.left = GetFixedColumnWidth(TRUE);
+ int offset = -rect.Width();
+ int pos = __max(0, scrollPos + offset);
+ SetScrollPos32(SB_HORZ, pos);
+ // LUC
+ rect.left = GetFixedColumnWidth(bIncludeFreezedCells);
+ InvalidateRect(rect);
+ }
+ break;
+
+ case SB_THUMBPOSITION:
+ case SB_THUMBTRACK:
+ {
+ SetScrollPos32(SB_HORZ, GetScrollPos32(SB_HORZ, TRUE));
+ m_idTopLeftCell.row = -1;
+ CCellID idNewTopLeft = GetTopleftNonFixedCell();
+ if (idNewTopLeft != idTopLeft)
+ {
+ // LUC
+ rect.left = GetFixedColumnWidth(bIncludeFreezedCells);
+ InvalidateRect(rect);
+ }
+ }
+ break;
+
+ case SB_LEFT:
+ if (scrollPos > 0)
+ {
+ SetScrollPos32(SB_HORZ, 0);
+ Invalidate();
+ }
+ break;
+
+ case SB_RIGHT:
+ if (scrollPos < m_nHScrollMax)
+ {
+ SetScrollPos32(SB_HORZ, m_nHScrollMax);
+ Invalidate();
+ }
+ break;
+
+
+ default:
+ break;
+ }
+}
+
+// Handle vert scrollbar notifications
+void CGridCtrl::OnVScroll(UINT nSBCode, UINT /*nPos*/, CScrollBar* /*pScrollBar*/)
+{
+ EndEditing();
+
+#ifndef GRIDCONTROL_NO_TITLETIPS
+ m_TitleTip.Hide(); // hide any titletips
+#endif
+
+ // Get the scroll position ourselves to ensure we get a 32 bit value
+ int scrollPos = GetScrollPos32(SB_VERT);
+
+ CCellID idTopLeft = GetTopleftNonFixedCell();
+
+ CRect rect;
+ GetClientRect(rect);
+
+ // LUC
+ BOOL bIncludeFreezedCells = FALSE;
+
+ switch (nSBCode)
+ {
+ case SB_LINEDOWN:
+ if (scrollPos < m_nVScrollMax)
+ {
+ // may have contiguous hidden rows. Blow by them
+ while( idTopLeft.row < (GetRowCount()-1)
+ && GetRowHeight( idTopLeft.row) < 1 )
+ {
+ idTopLeft.row++;
+ }
+
+ int yScroll = GetRowHeight(idTopLeft.row);
+ SetScrollPos32(SB_VERT, scrollPos + yScroll);
+ if (GetScrollPos32(SB_VERT) == scrollPos)
+ break; // didn't work
+
+ // LUC
+ rect.top = GetFixedRowHeight(bIncludeFreezedCells);
+ //rect.top = GetFixedRowHeight() + yScroll;
+ //ScrollWindow(0, -yScroll, rect);
+ //rect.top = rect.bottom - yScroll;
+ InvalidateRect(rect);
+ }
+ break;
+
+ case SB_LINEUP:
+ if (scrollPos > 0 && idTopLeft.row > GetFixedRowCount(TRUE))
+ {
+ int iRowToUse = idTopLeft.row-1;
+ // may have contiguous hidden rows. Blow by them
+ while( iRowToUse > GetFixedRowCount(TRUE)
+ && GetRowHeight( iRowToUse) < 1 )
+ {
+ iRowToUse--;
+ }
+
+ int yScroll = GetRowHeight( iRowToUse);
+ SetScrollPos32(SB_VERT, __max(0, scrollPos - yScroll));
+ // LUC
+ rect.top = GetFixedRowHeight(bIncludeFreezedCells);
+ //ScrollWindow(0, yScroll, rect);
+ //rect.bottom = rect.top + yScroll;
+ InvalidateRect(rect);
+ }
+ break;
+
+ case SB_PAGEDOWN:
+ if (scrollPos < m_nVScrollMax)
+ {
+ // LUC
+ rect.top = GetFixedRowHeight(TRUE);
+ scrollPos = min(m_nVScrollMax, scrollPos + rect.Height());
+ SetScrollPos32(SB_VERT, scrollPos);
+ // LUC
+ rect.top = GetFixedRowHeight(bIncludeFreezedCells);
+ InvalidateRect(rect);
+ }
+ break;
+
+ case SB_PAGEUP:
+ if (scrollPos > 0)
+ {
+ // LUC
+ rect.top = GetFixedRowHeight(TRUE);
+ int offset = -rect.Height();
+ int pos = __max(0, scrollPos + offset);
+ SetScrollPos32(SB_VERT, pos);
+ // LUC
+ rect.top = GetFixedRowHeight(bIncludeFreezedCells);
+ InvalidateRect(rect);
+ }
+ break;
+
+ case SB_THUMBPOSITION:
+ case SB_THUMBTRACK:
+ {
+ SetScrollPos32(SB_VERT, GetScrollPos32(SB_VERT, TRUE));
+ m_idTopLeftCell.row = -1;
+ CCellID idNewTopLeft = GetTopleftNonFixedCell();
+ if (idNewTopLeft != idTopLeft)
+ {
+ // LUC
+ rect.top = GetFixedRowHeight(bIncludeFreezedCells);
+ InvalidateRect(rect);
+ }
+ }
+ break;
+
+ case SB_TOP:
+ if (scrollPos > 0)
+ {
+ SetScrollPos32(SB_VERT, 0);
+ Invalidate();
+ }
+ break;
+
+ case SB_BOTTOM:
+ if (scrollPos < m_nVScrollMax)
+ {
+ SetScrollPos32(SB_VERT, m_nVScrollMax);
+ Invalidate();
+ }
+
+ default:
+ break;
+ }
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// CGridCtrl implementation functions
+
+void CGridCtrl::OnDraw(CDC* pDC)
+{
+ if (!m_bAllowDraw)
+ return;
+
+ CRect clipRect;
+ if (pDC->GetClipBox(&clipRect) == ERROR)
+ return;
+
+ EraseBkgnd(pDC); // OnEraseBkgnd does nothing, so erase bkgnd here.
+ // This necessary since we may be using a Memory DC.
+
+#ifdef _DEBUG
+ LARGE_INTEGER iStartCount;
+ QueryPerformanceCounter(&iStartCount);
+#endif
+
+ CRect rc;
+ GetClientRect(rc);
+
+ CRect rect;
+ int row, col;
+ CGridCellBase* pCell;
+
+ // LUC
+ int nFixedRowHeight = GetFixedRowHeight(TRUE);
+ int nFixedColWidth = GetFixedColumnWidth(TRUE);
+
+ CCellID idTopLeft = GetTopleftNonFixedCell();
+ int minVisibleRow = idTopLeft.row,
+ minVisibleCol = idTopLeft.col;
+
+ CRect VisRect;
+ CCellRange VisCellRange = GetVisibleNonFixedCellRange(VisRect);
+ int maxVisibleRow = VisCellRange.GetMaxRow(),
+ maxVisibleCol = VisCellRange.GetMaxCol();
+
+ if (GetVirtualMode())
+ SendCacheHintToParent(VisCellRange);
+
+ // draw top-left cells 0..m_nFixedRows-1, 0..m_nFixedCols-1
+ rect.bottom = -1;
+ int nFixedRows = m_nFixedRows + m_nFreezedRows;
+ int nFixedCols = m_nFixedCols + m_nFreezedCols;
+ for (row = 0; row < nFixedRows; row++)
+ {
+ if (GetRowHeight(row) <= 0) continue;
+
+ rect.top = rect.bottom+1;
+ rect.bottom = rect.top + GetRowHeight(row)-1;
+ rect.right = -1;
+
+ for (col = 0; col < nFixedCols; col++)
+ {
+ if (GetColumnWidth(col) <= 0) continue;
+
+ rect.left = rect.right+1;
+ rect.right = rect.left + GetColumnWidth(col)-1;
+
+ pCell = GetCell(row, col);
+ if (pCell)
+ {
+ pCell->SetCoords(row,col);
+ pCell->Draw(pDC, row, col, rect, FALSE);
+ }
+ }
+ }
+
+
+ // draw fixed column cells: m_nFixedRows..n, 0..m_nFixedCols-1
+ rect.bottom = nFixedRowHeight-1;
+ for (row = minVisibleRow; row <= maxVisibleRow; row++)
+ {
+ if (GetRowHeight(row) <= 0) continue;
+
+ rect.top = rect.bottom+1;
+ rect.bottom = rect.top + GetRowHeight(row)-1;
+
+ // rect.bottom = bottom pixel of previous row
+ if (rect.top > clipRect.bottom)
+ break; // Gone past cliprect
+ if (rect.bottom < clipRect.top)
+ continue; // Reached cliprect yet?
+
+ rect.right = -1;
+ for (col = 0; col < nFixedCols; col++)
+ {
+ if (GetColumnWidth(col) <= 0) continue;
+
+ rect.left = rect.right+1;
+ rect.right = rect.left + GetColumnWidth(col)-1;
+
+ if (rect.left > clipRect.right)
+ break; // gone past cliprect
+ if (rect.right < clipRect.left)
+ continue; // Reached cliprect yet?
+
+ pCell = GetCell(row, col);
+ if (pCell)
+ {
+ pCell->SetCoords(row,col);
+ pCell->Draw(pDC, row, col, rect, FALSE);
+ }
+ }
+ }
+
+
+ // draw fixed row cells 0..m_nFixedRows, m_nFixedCols..n
+ rect.bottom = -1;
+ for (row = 0; row < nFixedRows; row++)
+ {
+ if (GetRowHeight(row) <= 0) continue;
+
+ rect.top = rect.bottom+1;
+ rect.bottom = rect.top + GetRowHeight(row)-1;
+
+ // rect.bottom = bottom pixel of previous row
+ if (rect.top > clipRect.bottom)
+ break; // Gone past cliprect
+ if (rect.bottom < clipRect.top)
+ continue; // Reached cliprect yet?
+
+ rect.right = nFixedColWidth-1;
+ for (col = minVisibleCol; col <= maxVisibleCol; col++)
+ {
+ if (GetColumnWidth(col) <= 0) continue;
+
+ rect.left = rect.right+1;
+ rect.right = rect.left + GetColumnWidth(col)-1;
+
+ if (rect.left > clipRect.right)
+ break; // gone past cliprect
+ if (rect.right < clipRect.left)
+ continue; // Reached cliprect yet?
+
+ pCell = GetCell(row, col);
+ if (pCell)
+ {
+ pCell->SetCoords(row,col);
+ // LUC
+ if(!m_bShowHorzNonGridArea && (col == m_nCols - 1))
+ {
+ pCell->Draw(pDC, row, col, rect, FALSE);
+
+ if(rect.right < rc.right)
+ {
+ CRect rcFill(rect.right + 1, rect.top, rc.right - 2, rect.bottom);
+
+ CGridCell cell;
+ cell.SetGrid(this);
+
+ DWORD dwState = pCell->GetState() & ~(GVIS_SELECTED | GVIS_FOCUSED);
+ cell.SetState(dwState);
+
+ int nSortColumn = GetSortColumn();
+ m_nSortColumn = -1;
+
+ cell.Draw(pDC, row, col, rcFill, TRUE);
+
+ if(!(pCell->GetState() & GVIS_FIXED))
+ {
+ rcFill.right++;
+ rcFill.bottom++;
+ pDC->Draw3dRect(rcFill, GetTextBkColor(), m_crGridLineColour);
+ }
+
+ m_nSortColumn = nSortColumn;
+ }
+ }
+ else
+ {
+ pCell->Draw(pDC, row, col, rect, FALSE);
+ }
+ }
+ }
+ }
+
+ // draw rest of non-fixed cells
+ rect.bottom = nFixedRowHeight-1;
+ for (row = minVisibleRow; row <= maxVisibleRow; row++)
+ {
+ if (GetRowHeight(row) <= 0) continue;
+
+ rect.top = rect.bottom+1;
+ rect.bottom = rect.top + GetRowHeight(row)-1;
+
+ // rect.bottom = bottom pixel of previous row
+ if (rect.top > clipRect.bottom)
+ break; // Gone past cliprect
+ if (rect.bottom < clipRect.top)
+ continue; // Reached cliprect yet?
+
+ rect.right = nFixedColWidth-1;
+ for (col = minVisibleCol; col <= maxVisibleCol; col++)
+ {
+ if (GetColumnWidth(col) <= 0) continue;
+
+ rect.left = rect.right+1;
+ rect.right = rect.left + GetColumnWidth(col)-1;
+
+ if (rect.left > clipRect.right)
+ break; // gone past cliprect
+ if (rect.right < clipRect.left)
+ continue; // Reached cliprect yet?
+
+ pCell = GetCell(row, col);
+ // TRACE(_T("Cell %d,%d type: %s\n"), row, col, pCell->GetRuntimeClass()->m_lpszClassName);
+ if (pCell)
+ {
+ pCell->SetCoords(row,col);
+ // LUC
+ if(!m_bShowHorzNonGridArea && (col == m_nCols - 1))
+ {
+ if(rect.right < rc.right)
+ {
+ pCell->Draw(pDC, row, col, rect, FALSE);
+
+ CRect rcFill(rect.right + 1, rect.top, rc.right - 1, rect.bottom);
+ pDC->FillSolidRect(rcFill, GetTextBkColor());
+
+ rcFill.right++;
+ rcFill.bottom++;
+ pDC->Draw3dRect(rcFill, GetTextBkColor(), m_crGridLineColour);
+ }
+
+ }
+ else
+ {
+ pCell->Draw(pDC, row, col, rect, FALSE);
+ }
+ }
+ }
+ }
+
+ CPen pen;
+ pen.CreatePen(PS_SOLID, 0, m_crGridLineColour);
+ pDC->SelectObject(&pen);
+
+ // draw vertical lines (drawn at ends of cells)
+ if (m_nGridLines == GVL_BOTH || m_nGridLines == GVL_VERT)
+ {
+ // LUC
+ //int x = nFixedColWidth;
+ int x = GetFixedColumnWidth();
+
+ // LUC
+ //for (col = minVisibleCol; col < maxVisibleCol; col++)
+ int nFixedRowHeightExcludingFreezedRows = GetFixedRowHeight();
+ for (col = m_nFixedCols; col <= maxVisibleCol; col++)
+ {
+ if (GetColumnWidth(col) <= 0) continue;
+
+ if(col == (m_nFixedCols + m_nFreezedCols))
+ {
+ col = minVisibleCol;
+ }
+
+ x += GetColumnWidth(col);
+ //pDC->MoveTo(x-1, nFixedRowHeight);
+ pDC->MoveTo(x-1, nFixedRowHeightExcludingFreezedRows);
+ pDC->LineTo(x-1, VisRect.bottom);
+ }
+ }
+
+ // draw horizontal lines (drawn at bottom of each cell)
+ if (m_nGridLines == GVL_BOTH || m_nGridLines == GVL_HORZ)
+ {
+ // LUC
+ //int y = nFixedRowHeight;
+ int y = GetFixedRowHeight();
+ //for (row = minVisibleRow; row <= maxVisibleRow; row++)
+ int nFixedColumnWidthExcludingFreezedColumns = GetFixedColumnWidth();
+ for (row = m_nFixedRows; row <= maxVisibleRow; row++)
+ {
+ if (GetRowHeight(row) <= 0) continue;
+
+ if(row == (m_nFixedRows + m_nFreezedRows))
+ {
+ row = minVisibleRow;
+ }
+
+ y += GetRowHeight(row);
+ //pDC->MoveTo(nFixedColWidth, y-1);
+ pDC->MoveTo(nFixedColumnWidthExcludingFreezedColumns, y-1);
+ // LUC
+ pDC->LineTo(VisRect.right, y-1);
+ }
+ }
+
+ // LUC : Merge Cell
+ m_bDrawingMergedCell = TRUE;
+ INT_PTR size = m_arMergedCells.GetSize();
+ if(size > 0)
+ {
+ CRect rcMergeRect;
+ for(INT_PTR i = 0; i < size; i++)
+ {
+ m_nCurrentMergeID = i;
+ if(GetMergedCellRect(m_arMergedCells[i], rcMergeRect))
+ {
+ rcMergeRect.right--;
+ rcMergeRect.bottom--;
+
+ pCell = GetCell(m_arMergedCells[i].GetMinRow(), m_arMergedCells[i].GetMinCol());
+ if (pCell)
+ {
+ pCell->Draw(pDC, m_arMergedCells[i].GetMinRow(), m_arMergedCells[i].GetMinCol(), rcMergeRect, TRUE);
+ }
+ }
+ }
+ }
+ m_bDrawingMergedCell = FALSE;
+ m_nCurrentMergeID = -1;
+
+ // LUC:
+ // Finally we can draw a line for the Freezed Frame
+ ////
+ pen.DeleteObject();
+ pen.CreatePen(PS_SOLID, 0, RGB(0, 0, 255));
+ pDC->SelectObject(&pen);
+ if(m_nFreezedRows > 0)
+ {
+ pDC->MoveTo(0, nFixedRowHeight);
+ pDC->LineTo(rc.right, nFixedRowHeight);
+ }
+ if(m_nFreezedCols > 0)
+ {
+ pDC->MoveTo(nFixedColWidth, 0);
+ pDC->LineTo(nFixedColWidth, rc.bottom);
+ }
+
+ pDC->SelectStockObject(NULL_PEN);
+
+ // Let parent know it can discard it's data if it needs to.
+ if (GetVirtualMode())
+ SendCacheHintToParent(CCellRange(-1,-1,-1,-1));
+
+#ifdef _DEBUG
+ LARGE_INTEGER iEndCount;
+ QueryPerformanceCounter(&iEndCount);
+ //TRACE1("Draw counter ticks: %d\n", iEndCount.LowPart-iStartCount.LowPart);
+#endif
+
+}
+
+////////////////////////////////////////////////////////////////////////////////////////
+// CGridCtrl Cell selection stuff
+
+// Is a given cell designation valid (ie within the bounds of our number
+// of columns/rows)?
+BOOL CGridCtrl::IsValid(int nRow, int nCol) const
+{
+ return (nRow >= 0 && nRow < m_nRows && nCol >= 0 && nCol < m_nCols);
+}
+
+BOOL CGridCtrl::IsValid(const CCellID& cell) const
+{
+ return IsValid(cell.row, cell.col);
+}
+
+// Is a given cell range valid (ie within the bounds of our number
+// of columns/rows)?
+BOOL CGridCtrl::IsValid(const CCellRange& range) const
+{
+ return (range.GetMinRow() >= 0 && range.GetMinCol() >= 0 &&
+ range.GetMaxRow() >= 0 && range.GetMaxCol() >= 0 &&
+ range.GetMaxRow() < m_nRows && range.GetMaxCol() < m_nCols &&
+ range.GetMinRow() <= range.GetMaxRow() && range.GetMinCol() <= range.GetMaxCol());
+}
+
+// Enables/Disables redraw for certain operations like columns auto-sizing etc,
+// but not for user caused things such as selection changes.
+void CGridCtrl::SetRedraw(BOOL bAllowDraw, BOOL bResetScrollBars /* = FALSE */)
+{
+// TRACE(_T("%s: Setting redraw to %s\n"),
+// GetRuntimeClass()->m_lpszClassName, bAllowDraw? _T("TRUE") : _T("FALSE"));
+
+ if (bAllowDraw && !m_bAllowDraw)
+ {
+ m_bAllowDraw = TRUE;
+ Refresh();
+ }
+
+ m_bAllowDraw = bAllowDraw;
+ if (bResetScrollBars)
+ ResetScrollBars();
+}
+
+// Forces a redraw of a cell immediately (using a direct DC construction,
+// or the supplied dc)
+BOOL CGridCtrl::RedrawCell(const CCellID& cell, CDC* pDC /* = NULL */)
+{
+ return RedrawCell(cell.row, cell.col, pDC);
+}
+
+BOOL CGridCtrl::RedrawCell(int nRow, int nCol, CDC* pDC /* = NULL */)
+{
+ BOOL bResult = TRUE;
+ BOOL bMustReleaseDC = FALSE;
+
+ if (!m_bAllowDraw || !IsCellVisible(nRow, nCol))
+ return FALSE;
+
+ CRect rect;
+ if (!GetCellRect(nRow, nCol, rect))
+ return FALSE;
+
+ // LUC
+ BOOL bIsMergeCell = GetTopLeftMergedCell(nRow, nCol, rect);
+
+ if (!pDC)
+ {
+ pDC = GetDC();
+ if (pDC)
+ bMustReleaseDC = TRUE;
+ }
+
+ if (pDC)
+ {
+ // Redraw cells directly
+ if (nRow < m_nFixedRows || nCol < m_nFixedCols)
+ {
+ CGridCellBase* pCell = GetCell(nRow, nCol);
+ if (pCell)
+ bResult = pCell->Draw(pDC, nRow, nCol, rect, TRUE);
+ }
+ else
+ {
+ CGridCellBase* pCell = GetCell(nRow, nCol);
+ if (pCell)
+ bResult = pCell->Draw(pDC, nRow, nCol, rect, TRUE);
+
+ // Since we have erased the background, we will need to redraw the gridlines
+ CPen pen;
+ pen.CreatePen(PS_SOLID, 0, m_crGridLineColour);
+
+ CPen* pOldPen = (CPen*) pDC->SelectObject(&pen);
+ if (m_nGridLines == GVL_BOTH || m_nGridLines == GVL_HORZ)
+ {
+ pDC->MoveTo(rect.left, rect.bottom);
+ pDC->LineTo(rect.right + 1, rect.bottom);
+ }
+ if (m_nGridLines == GVL_BOTH || m_nGridLines == GVL_VERT)
+ {
+ pDC->MoveTo(rect.right, rect.top);
+ pDC->LineTo(rect.right, rect.bottom + 1);
+ }
+ pDC->SelectObject(pOldPen);
+ }
+ } else
+ InvalidateRect(rect, TRUE); // Could not get a DC - invalidate it anyway
+ // and hope that OnPaint manages to get one
+
+ if (bMustReleaseDC)
+ ReleaseDC(pDC);
+
+ // LUC : if this is a merge cell then we have to make sure there are no drawing problem becoz of direct redraw of cell
+ // specially becoz of the freeze pane lines
+ if(bIsMergeCell)
+ {
+ InvalidateRect(rect, TRUE);
+ }
+
+ return bResult;
+}
+
+// redraw a complete row
+BOOL CGridCtrl::RedrawRow(int row)
+{
+ BOOL bResult = TRUE;
+
+ CDC* pDC = GetDC();
+ for (int col = 0; col < GetColumnCount(); col++)
+ bResult = RedrawCell(row, col, pDC) && bResult;
+ if (pDC)
+ ReleaseDC(pDC);
+
+ return bResult;
+}
+
+// redraw a complete column
+BOOL CGridCtrl::RedrawColumn(int col)
+{
+ BOOL bResult = TRUE;
+
+ CDC* pDC = GetDC();
+ for (int row = 0; row < GetRowCount(); row++)
+ bResult = RedrawCell(row, col, pDC) && bResult;
+ if (pDC)
+ ReleaseDC(pDC);
+
+ return bResult;
+}
+
+
+// Sets the currently selected cell, returning the previous current cell
+CCellID CGridCtrl::SetFocusCell(int nRow, int nCol)
+{
+ return SetFocusCell(CCellID(nRow, nCol));
+}
+
+CCellID CGridCtrl::SetFocusCell(CCellID cell)
+{
+ if (cell == m_idCurrentCell)
+ return m_idCurrentCell;
+
+ CCellID idPrev = m_idCurrentCell;
+
+ // EFW - Bug Fix - Force focus to be in a non-fixed cell
+ if (cell.row != -1 && cell.row < GetFixedRowCount(m_bExcludeFreezedRowsFromSelection))
+ cell.row = GetFixedRowCount(m_bExcludeFreezedRowsFromSelection);
+ if (cell.col != -1 && cell.col < GetFixedColumnCount(m_bExcludeFreezedColsFromSelection))
+ cell.col = GetFixedColumnCount(m_bExcludeFreezedColsFromSelection);
+
+ m_idCurrentCell = cell;
+
+ if (IsValid(idPrev))
+ {
+ SetItemState(idPrev.row, idPrev.col,
+ GetItemState(idPrev.row, idPrev.col) & ~GVIS_FOCUSED);
+ RedrawCell(idPrev); // comment to reduce flicker
+
+ if (GetTrackFocusCell() && idPrev.col != m_idCurrentCell.col)
+ for (int row = 0; row < m_nFixedRows; row++)
+ RedrawCell(row, idPrev.col);
+ if (GetTrackFocusCell() && idPrev.row != m_idCurrentCell.row)
+ for (int col = 0; col < m_nFixedCols; col++)
+ RedrawCell(idPrev.row, col);
+ }
+
+ if (IsValid(m_idCurrentCell))
+ {
+ SetItemState(m_idCurrentCell.row, m_idCurrentCell.col,
+ GetItemState(m_idCurrentCell.row, m_idCurrentCell.col) | GVIS_FOCUSED);
+
+ RedrawCell(m_idCurrentCell); // comment to reduce flicker
+
+ if (GetTrackFocusCell() && idPrev.col != m_idCurrentCell.col)
+ for (int row = 0; row < m_nFixedRows; row++)
+ RedrawCell(row, m_idCurrentCell.col);
+ if (GetTrackFocusCell() && idPrev.row != m_idCurrentCell.row)
+ for (int col = 0; col < m_nFixedCols; col++)
+ RedrawCell(m_idCurrentCell.row, col);
+
+ // EFW - New addition. If in list mode, make sure the selected
+ // row highlight follows the cursor.
+ // Removed by C Maunder 27 May
+ //if (m_bListMode)
+ //{
+ // m_PrevSelectedCellMap.RemoveAll();
+ // m_MouseMode = MOUSE_SELECT_ROW;
+ // OnSelecting(m_idCurrentCell);
+
+ // Leave this off so that you can still drag the highlight around
+ // without selecting rows.
+ // m_MouseMode = MOUSE_NOTHING;
+ //}
+
+ }
+
+ return idPrev;
+}
+
+// Sets the range of currently selected cells
+void CGridCtrl::SetSelectedRange(const CCellRange& Range,
+ BOOL bForceRepaint /* = FALSE */, BOOL bSelectCells/*=TRUE*/)
+{
+ SetSelectedRange(Range.GetMinRow(), Range.GetMinCol(),
+ Range.GetMaxRow(), Range.GetMaxCol(),
+ bForceRepaint, bSelectCells);
+}
+
+void CGridCtrl::SetSelectedRange(int nMinRow, int nMinCol, int nMaxRow, int nMaxCol,
+ BOOL bForceRepaint /* = FALSE */, BOOL bSelectCells/*=TRUE*/)
+{
+ if (!m_bEnableSelection)
+ return;
+
+ CWaitCursor wait; // Thomas Haase
+
+
+ CDC* pDC = NULL;
+ if (bForceRepaint)
+ pDC = GetDC();
+
+ // Only redraw visible cells
+ CCellRange VisCellRange, FixedVisCellRange;
+ if (IsWindow(GetSafeHwnd()))
+
+ {
+ VisCellRange = GetVisibleNonFixedCellRange(NULL, 0);
+ FixedVisCellRange = GetVisibleFixedCellRange();
+ }
+
+ // EFW - Bug fix - Don't allow selection of fixed rows
+ // LUC
+ int Left= (m_AllowSelectRowInFixedCol ? 0 : GetFixedColumnCount(m_bExcludeFreezedColsFromSelection));
+
+ if(nMinRow >= 0 && nMinRow < GetFixedRowCount(m_bExcludeFreezedRowsFromSelection))
+ nMinRow = GetFixedRowCount(m_bExcludeFreezedRowsFromSelection);
+ if(nMaxRow >= 0 && nMaxRow < GetFixedRowCount(m_bExcludeFreezedRowsFromSelection))
+ nMaxRow = GetFixedRowCount(m_bExcludeFreezedRowsFromSelection);
+ if(nMinCol >= 0 && nMinCol < Left)
+ nMinCol = GetFixedColumnCount(m_bExcludeFreezedColsFromSelection);
+ if(nMaxCol >= 0 && nMaxCol < Left)
+ nMaxCol = GetFixedColumnCount(m_bExcludeFreezedColsFromSelection);
+
+ // LUC
+ for(int row = nMinRow; row <= nMaxRow; row++)
+ {
+ for(int col = nMinCol; col <= nMaxCol; col++)
+ {
+ int nMergedMinRow = row, nMergedMinCol = col;
+ if(GetTopLeftMergedCell(nMergedMinRow, nMergedMinCol, rectNull))
+ {
+ if(nMinRow > nMergedMinRow)
+ {
+ nMinRow = nMergedMinRow;
+ }
+ if(nMinCol > nMergedMinCol)
+ {
+ nMinCol = nMergedMinCol;
+ }
+ }
+ int nMergedMaxRow = row, nMergedMaxCol = col;
+
+ if(GetBottomRightMergedCell(nMergedMaxRow, nMergedMaxCol, rectNull))
+ {
+ if(nMaxRow < nMergedMaxRow)
+ {
+ nMaxRow = nMergedMaxRow;
+ }
+ if(nMaxCol < nMergedMaxCol)
+ {
+ nMaxCol = nMergedMaxCol;
+ }
+
+ // let's try to make it a bit efficient
+ row = nMergedMaxRow;
+ col = nMergedMaxCol;
+ }
+
+ }
+ }
+ ////
+ // If we are selecting cells, then first clear out the list of currently selected cells, then
+ if (bSelectCells)
+ {
+ POSITION pos;
+
+ // Unselect all previously selected cells
+ for (pos = m_SelectedCellMap.GetStartPosition(); pos != NULL; )
+ {
+ DWORD key;
+ CCellID cell;
+ m_SelectedCellMap.GetNextAssoc(pos, key, (CCellID&)cell);
+
+ // Reset the selection flag on the cell
+ if (IsValid(cell))
+ {
+ // This will remove the cell from the m_SelectedCellMap map
+ SetItemState(cell.row, cell.col,
+ GetItemState(cell.row, cell.col) & ~GVIS_SELECTED);
+
+ // If this is to be reselected, continue on past the redraw
+ if (nMinRow <= cell.row && cell.row <= nMaxRow &&
+ nMinCol <= cell.col && cell.col <= nMaxCol)
+ continue;
+
+ if ( (VisCellRange.IsValid() && VisCellRange.InRange( cell )) || FixedVisCellRange.InRange( cell ) )
+ {
+ if (bForceRepaint && pDC) // Redraw NOW
+ RedrawCell(cell.row, cell.col, pDC);
+ else
+ InvalidateCellRect(cell); // Redraw at leisure
+ }
+ }
+ else
+ {
+ m_SelectedCellMap.RemoveKey( key); // if it's not valid, get rid of it!
+ }
+ }
+
+ // if we are selecting cells, and there are previous selected cells to be retained
+ // (eg Ctrl is being held down) then copy them to the newly created list, and mark
+ // all these cells as selected
+ // Note that if we are list mode, single row selection, then we won't be adding
+ // the previous cells. Only the current row of cells will be added (see below)
+ if (!GetSingleRowSelection() &&
+ nMinRow >= 0 && nMinCol >= 0 && nMaxRow >= 0 && nMaxCol >= 0)
+ {
+ for (pos = m_PrevSelectedCellMap.GetStartPosition(); pos != NULL; /* nothing */)
+ {
+ DWORD key;
+ CCellID cell;
+ m_PrevSelectedCellMap.GetNextAssoc(pos, key, (CCellID&)cell);
+
+ if (!IsValid(cell))
+ continue;
+
+ int nState = GetItemState(cell.row, cell.col);
+
+ // Set state as Selected. This will add the cell to m_SelectedCellMap
+ SetItemState(cell.row, cell.col, nState | GVIS_SELECTED);
+
+ if (( VisCellRange.IsValid() && VisCellRange.InRange( cell )) || FixedVisCellRange.InRange( cell ) )
+ {
+ // Redraw (immediately or at leisure)
+ if (bForceRepaint && pDC)
+ RedrawCell(cell.row, cell.col, pDC);
+ else
+ InvalidateCellRect(cell);
+ }
+ }
+ }
+ }
+
+ // Now select/deselect all cells in the cell range specified. If selecting, and the cell
+ // has already been marked as selected (above) then ignore it. If we are deselecting and
+ // the cell isn't selected, then ignore
+ if (nMinRow >= 0 && nMinCol >= 0 && nMaxRow >= 0 && nMaxCol >= 0 &&
+ nMaxRow < m_nRows && nMaxCol < m_nCols &&
+ nMinRow <= nMaxRow && nMinCol <= nMaxCol)
+ {
+ for (int row = nMinRow; row <= nMaxRow; row++)
+ for (int col = nMinCol; col <= nMaxCol; col++)
+ {
+ BOOL bCellSelected = IsCellSelected(row, col);
+ if (bSelectCells == bCellSelected)
+ continue; // Already selected or deselected - ignore
+
+ // Set the selected state. This will add/remove the cell to m_SelectedCellMap
+ if (bSelectCells)
+ SetItemState(row, col, GetItemState(row, col) | GVIS_SELECTED);
+ else
+ SetItemState(row, col, GetItemState(row, col) & ~GVIS_SELECTED);
+
+ if ( (VisCellRange.IsValid() && VisCellRange.InRange(row, col)) || FixedVisCellRange.InRange(row, col) )
+ {
+ // Redraw (immediately or at leisure)
+ if (bForceRepaint && pDC)
+ RedrawCell(row, col, pDC);
+ else
+ InvalidateCellRect(row, col);
+ }
+ }
+ }
+ // TRACE(_T("%d cells selected.\n"), m_SelectedCellMap.GetCount());
+
+ if (pDC != NULL)
+ ReleaseDC(pDC);
+}
+
+// selects all cells
+void CGridCtrl::SelectAllCells()
+{
+ if (!m_bEnableSelection)
+ return;
+
+ SetSelectedRange(m_nFixedRows, m_nFixedCols, GetRowCount()-1, GetColumnCount()-1);
+}
+
+// selects columns
+void CGridCtrl::SelectColumns(CCellID currentCell,
+ BOOL bForceRedraw /*=FALSE*/, BOOL bSelectCells /*=TRUE*/)
+{
+ if (!m_bEnableSelection)
+ return;
+
+ //if (currentCell.col == m_idCurrentCell.col) return;
+ if (currentCell.col < m_nFixedCols)
+ return;
+ if (!IsValid(currentCell))
+ return;
+
+ if (GetSingleColSelection())
+ SetSelectedRange(GetFixedRowCount(), currentCell.col,
+ GetRowCount()-1, currentCell.col,
+ bForceRedraw, bSelectCells);
+ else
+ SetSelectedRange(GetFixedRowCount(),
+ min(m_SelectionStartCell.col, currentCell.col),
+ GetRowCount()-1,
+ max(m_SelectionStartCell.col, currentCell.col),
+ bForceRedraw, bSelectCells);
+}
+
+// selects rows
+void CGridCtrl::SelectRows(CCellID currentCell,
+ BOOL bForceRedraw /*=FALSE*/, BOOL bSelectCells /*=TRUE*/)
+{
+ if (!m_bEnableSelection)
+ return;
+
+ //if (currentCell.row; == m_idCurrentCell.row) return;
+ if (currentCell.row < m_nFixedRows)
+ return;
+ if (!IsValid(currentCell))
+ return;
+ int Left = ( m_AllowSelectRowInFixedCol ? 0 : GetFixedColumnCount());
+ if (GetSingleRowSelection())
+ SetSelectedRange(currentCell.row, Left ,
+ currentCell.row, GetColumnCount()-1,
+ bForceRedraw, bSelectCells);
+ else
+ SetSelectedRange(min(m_SelectionStartCell.row, currentCell.row),
+ Left,
+ __max(m_SelectionStartCell.row, currentCell.row),
+ GetColumnCount()-1,
+ bForceRedraw, bSelectCells);
+}
+
+// selects cells
+void CGridCtrl::SelectCells(CCellID currentCell,
+ BOOL bForceRedraw /*=FALSE*/, BOOL bSelectCells /*=TRUE*/)
+{
+ if (!m_bEnableSelection)
+ return;
+
+ int row = currentCell.row;
+ int col = currentCell.col;
+ // LUC
+ if (row < GetFixedRowCount(m_bExcludeFreezedRowsFromSelection) || col < GetFixedColumnCount(m_bExcludeFreezedColsFromSelection))
+ if (row < GetFixedRowCount() || col < GetFixedColumnCount())
+ {
+ return;
+ }
+ if (!IsValid(currentCell))
+ return;
+
+ // Prevent unnecessary redraws
+ //if (currentCell == m_LeftClickDownCell) return;
+ //else if (currentCell == m_idCurrentCell) return;
+
+ SetSelectedRange(min(m_SelectionStartCell.row, row),
+ min(m_SelectionStartCell.col, col),
+ __max(m_SelectionStartCell.row, row),
+ __max(m_SelectionStartCell.col, col),
+ bForceRedraw, bSelectCells);
+}
+
+// Called when mouse/keyboard selection is a-happening.
+void CGridCtrl::OnSelecting(const CCellID& currentCell)
+{
+ if (!m_bEnableSelection)
+ return;
+
+ switch (m_MouseMode)
+ {
+ case MOUSE_SELECT_ALL:
+ SelectAllCells();
+ break;
+ case MOUSE_SELECT_COL:
+ SelectColumns(currentCell, FALSE);
+ break;
+ case MOUSE_SELECT_ROW:
+ SelectRows(currentCell, FALSE);
+ break;
+ case MOUSE_SELECT_CELLS:
+ SelectCells(currentCell, FALSE);
+ break;
+ }
+
+ // EFW - Bug fix [REMOVED CJM: this will cause infinite loop in list mode]
+ // SetFocusCell(max(currentCell.row, m_nFixedRows), max(currentCell.col, m_nFixedCols));
+}
+
+void CGridCtrl::ValidateAndModifyCellContents(int nRow, int nCol, LPCTSTR strText)
+{
+ if (!IsCellEditable(nRow, nCol))
+ return;
+
+ if (SendMessageToParent(nRow, nCol, GVN_BEGINLABELEDIT) >= 0)
+ {
+ CString strCurrentText = GetItemText(nRow, nCol);
+ if (strCurrentText != strText)
+ {
+ SetItemText(nRow, nCol, strText);
+ if (ValidateEdit(nRow, nCol, strText) &&
+ SendMessageToParent(nRow, nCol, GVN_ENDLABELEDIT) >= 0)
+ {
+ SetModified(TRUE, nRow, nCol);
+ RedrawCell(nRow, nCol);
+ }
+ else
+ {
+ SetItemText(nRow, nCol, strCurrentText);
+ }
+ }
+ }
+}
+
+void CGridCtrl::ClearCells(CCellRange Selection)
+{
+ for (int row = Selection.GetMinRow(); row <= Selection.GetMaxRow(); row++)
+ {
+ for (int col = Selection.GetMinCol(); col <= Selection.GetMaxCol(); col++)
+ {
+ // don't clear hidden cells
+ if ( m_arRowHeights[row] > 0 && m_arColWidths[col] > 0 )
+ {
+ ValidateAndModifyCellContents(row, col, _T(""));
+ }
+ }
+ }
+ Refresh();
+}
+
+#ifndef GRIDCONTROL_NO_CLIPBOARD
+
+////////////////////////////////////////////////////////////////////////////////////////
+// Clipboard functions
+
+// Deletes the contents from the selected cells
+void CGridCtrl::CutSelectedText()
+{
+ if (!IsEditable())
+ return;
+
+ for (POSITION pos = m_SelectedCellMap.GetStartPosition(); pos != NULL; )
+ {
+ DWORD key;
+ CCellID cell;
+ m_SelectedCellMap.GetNextAssoc(pos, key, (CCellID&)cell);
+ ValidateAndModifyCellContents(cell.row, cell.col, _T(""));
+ }
+}
+
+// Copies text from the selected cells to the clipboard
+COleDataSource* CGridCtrl::CopyTextFromGrid()
+{
+ USES_CONVERSION;
+
+ CCellRange Selection = GetSelectedCellRange();
+ if (!IsValid(Selection))
+ return NULL;
+
+ if (GetVirtualMode())
+ SendCacheHintToParent(Selection);
+
+ // Write to shared file (REMEBER: CF_TEXT is ANSI, not UNICODE, so we need to convert)
+ CSharedFile sf(GMEM_MOVEABLE | GMEM_DDESHARE | GMEM_ZEROINIT);
+
+ // Get a tab delimited string to copy to cache
+ CString str;
+ CGridCellBase *pCell;
+ for (int row = Selection.GetMinRow(); row <= Selection.GetMaxRow(); row++)
+ {
+ // don't copy hidden cells
+ if( m_arRowHeights[row] <= 0 )
+ continue;
+
+ str.Empty();
+ for (int col = Selection.GetMinCol(); col <= Selection.GetMaxCol(); col++)
+ {
+ // don't copy hidden cells
+ if( m_arColWidths[col] <= 0 )
+ continue;
+
+ pCell = GetCell(row, col);
+ if (pCell &&(pCell->GetState() & GVIS_SELECTED))
+ {
+ // if (!pCell->GetText())
+ // str += _T(" ");
+ // else
+ str += pCell->GetText();
+ }
+ if (col != Selection.GetMaxCol())
+ str += _T("\t");
+ }
+
+ if (row != Selection.GetMaxRow())
+ str += _T("\r\n");
+
+ sf.Write(T2A(str.GetBuffer(1)), str.GetLength());
+ str.ReleaseBuffer();
+ }
+
+ char c = '\0';
+ sf.Write(&c, 1);
+
+ if (GetVirtualMode())
+ SendCacheHintToParent(CCellRange(-1,-1,-1,-1));
+
+ DWORD dwLen = (DWORD) sf.GetLength();
+ HGLOBAL hMem = sf.Detach();
+ if (!hMem)
+ return NULL;
+
+ hMem = ::GlobalReAlloc(hMem, dwLen, GMEM_MOVEABLE | GMEM_DDESHARE | GMEM_ZEROINIT);
+ if (!hMem)
+ return NULL;
+
+ // Cache data
+ COleDataSource* pSource = new COleDataSource();
+ pSource->CacheGlobalData(CF_TEXT, hMem);
+
+ return pSource;
+}
+
+// Pastes text from the clipboard to the selected cells
+BOOL CGridCtrl::PasteTextToGrid(CCellID cell, COleDataObject* pDataObject,
+ BOOL bSelectPastedCells /*=TRUE*/)
+{
+ if (!IsValid(cell) || !IsCellEditable(cell) || !pDataObject->IsDataAvailable(CF_TEXT))
+ return FALSE;
+
+ // Get the text from the COleDataObject
+ HGLOBAL hmem = pDataObject->GetGlobalData(CF_TEXT);
+ CMemFile sf((BYTE*) ::GlobalLock(hmem), (UINT)::GlobalSize(hmem));
+
+ // CF_TEXT is ANSI text, so we need to allocate a char* buffer
+ // to hold this.
+ //LPTSTR szBuffer = new TCHAR[::GlobalSize(hmem)];
+ char* szBuffer = new char[::GlobalSize(hmem)];
+ if (!szBuffer)
+ return FALSE;
+
+ sf.Read(szBuffer, (UINT)::GlobalSize(hmem));
+ ::GlobalUnlock(hmem);
+
+ // Now store in generic TCHAR form so we no longer have to deal with
+ // ANSI/UNICODE problems
+ CString strText = szBuffer;
+ delete szBuffer;
+
+ // Parse text data and set in cells...
+ strText.LockBuffer();
+ CString strLine = strText;
+ int nLine = 0;
+
+ // Find the end of the first line
+ CCellRange PasteRange(cell.row, cell.col,-1,-1);
+ int nIndex;
+ do
+ {
+ int nColumn = 0;
+ nIndex = strLine.Find(_T("\n"));
+
+ // Store the remaining chars after the newline
+ CString strNext = (nIndex < 0)? _T("") : strLine.Mid(nIndex + 1);
+
+ // Remove all chars after the newline
+ if (nIndex >= 0)
+ strLine = strLine.Left(nIndex);
+
+ int nLineIndex = strLine.FindOneOf(_T("\t,"));
+ CString strCellText = (nLineIndex >= 0)? strLine.Left(nLineIndex) : strLine;
+
+ // skip hidden rows
+ int iRowVis = cell.row + nLine;
+ while( iRowVis < GetRowCount())
+ {
+ if( GetRowHeight( iRowVis) > 0)
+ break;
+ nLine++;
+ iRowVis++;
+ }
+
+ while (!strLine.IsEmpty())
+ {
+ // skip hidden columns
+ int iColVis = cell.col + nColumn;
+ while( iColVis < GetColumnCount())
+ {
+ if( GetColumnWidth( iColVis) > 0)
+ break;
+ nColumn++;
+ iColVis++;
+ }
+
+ CCellID TargetCell(iRowVis, iColVis);
+ if (IsValid(TargetCell))
+ {
+ strCellText.TrimLeft();
+ strCellText.TrimRight();
+
+ ValidateAndModifyCellContents(TargetCell.row, TargetCell.col, strCellText);
+
+ // Make sure cell is not selected to avoid data loss
+ SetItemState(TargetCell.row, TargetCell.col,
+ GetItemState(TargetCell.row, TargetCell.col) & ~GVIS_SELECTED);
+
+ if (iRowVis > PasteRange.GetMaxRow()) PasteRange.SetMaxRow(iRowVis);
+ if (iColVis > PasteRange.GetMaxCol()) PasteRange.SetMaxCol(iColVis);
+ }
+
+ strLine = (nLineIndex >= 0)? strLine.Mid(nLineIndex + 1) : _T("");
+ nLineIndex = strLine.FindOneOf(_T("\t,"));
+ strCellText = (nLineIndex >= 0)? strLine.Left(nLineIndex) : strLine;
+
+ nColumn++;
+ }
+
+ strLine = strNext;
+ nLine++;
+ } while (nIndex >= 0);
+
+ strText.UnlockBuffer();
+
+ if (bSelectPastedCells)
+ SetSelectedRange(PasteRange, TRUE);
+ else
+ {
+ ResetSelectedRange();
+ Refresh();
+ }
+
+ return TRUE;
+}
+#endif
+
+#ifndef GRIDCONTROL_NO_DRAGDROP
+
+// Start drag n drop
+void CGridCtrl::OnBeginDrag()
+{
+ COleDataSource* pSource = NULL;
+ if (!m_bAllowDragAndDrop && m_CurCol==-1)
+ return;
+
+ if (m_CurCol>=0) pSource = new COleDataSource();
+ if (!pSource && m_bAllowDragAndDrop) pSource = CopyTextFromGrid();
+ if (pSource)
+ {
+ SendMessageToParent(GetSelectedCellRange().GetTopLeft().row,
+ GetSelectedCellRange().GetTopLeft().col,
+ GVN_BEGINDRAG);
+
+ m_MouseMode = MOUSE_DRAGGING;
+ m_bLMouseButtonDown = FALSE;
+
+ DROPEFFECT dropEffect = pSource->DoDragDrop(DROPEFFECT_COPY | DROPEFFECT_MOVE);
+
+ if (dropEffect & DROPEFFECT_MOVE)
+ CutSelectedText();
+
+ if (pSource)
+ delete pSource; // Did not pass source to clipboard, so must delete
+
+ }
+}
+
+// Handle drag over grid
+DROPEFFECT CGridCtrl::OnDragOver(COleDataObject* pDataObject, DWORD dwKeyState,
+ CPoint point)
+{
+ // Find which cell we are over and drop-highlight it
+ CCellID cell = GetCellFromPt(point, FALSE);
+ bool Valid;
+ // Any text data available for us?
+ if(m_CurCol==-1)
+ {
+ if(m_bDragRowMode)
+ {
+ Valid = cell.col>=GetFixedColumnCount() && cell.row>=GetFixedRowCount();
+ }
+ else
+ {
+ if (!m_bAllowDragAndDrop || !IsEditable() || !pDataObject->IsDataAvailable(CF_TEXT))
+ return DROPEFFECT_NONE;
+ Valid = IsValid(cell)!=0;
+ }
+ }
+ else
+ {
+ Valid = cell.col>=GetFixedColumnCount() && cell.row<GetFixedRowCount() ;
+ }
+
+
+ // If not valid, set the previously drop-highlighted cell as no longer drop-highlighted
+ if (!Valid)
+ {
+ OnDragLeave();
+ m_LastDragOverCell = CCellID(-1,-1);
+ return DROPEFFECT_NONE;
+ }
+ if(m_CurCol==-1)
+ {
+ if (!m_bDragRowMode && !IsCellEditable(cell))
+ return DROPEFFECT_NONE;
+ }
+
+ // Have we moved over a different cell than last time?
+ if (cell != m_LastDragOverCell)
+ {
+ // Set the previously drop-highlighted cell as no longer drop-highlighted
+ if (IsValid(m_LastDragOverCell))
+ {
+ UINT nState = GetItemState(m_LastDragOverCell.row, m_LastDragOverCell.col);
+ SetItemState(m_LastDragOverCell.row, m_LastDragOverCell.col,
+ nState & ~GVIS_DROPHILITED);
+ RedrawCell(m_LastDragOverCell);
+ }
+
+ m_LastDragOverCell = cell;
+
+ // Set the new cell as drop-highlighted
+ if (IsValid(m_LastDragOverCell))
+ {
+ UINT nState = GetItemState(m_LastDragOverCell.row, m_LastDragOverCell.col);
+ SetItemState(m_LastDragOverCell.row, m_LastDragOverCell.col,
+ nState | GVIS_DROPHILITED);
+ RedrawCell(m_LastDragOverCell);
+ }
+ }
+
+ // Return an appropraite value of DROPEFFECT so mouse cursor is set properly
+ if (dwKeyState & MK_CONTROL)
+ return DROPEFFECT_COPY;
+ else
+ return DROPEFFECT_MOVE;
+}
+
+// Something has just been dragged onto the grid
+DROPEFFECT CGridCtrl::OnDragEnter(COleDataObject* pDataObject, DWORD dwKeyState,
+ CPoint point)
+{
+ // Any text data available for us?
+ m_LastDragOverCell = GetCellFromPt(point, m_CurCol>=0);
+ bool Valid;
+ if(m_CurCol==-1)
+ {
+ if (!m_bAllowDragAndDrop || !pDataObject->IsDataAvailable(CF_TEXT))
+ return DROPEFFECT_NONE;
+
+ // Find which cell we are over and drop-highlight it
+ if (!IsValid(m_LastDragOverCell))
+ return DROPEFFECT_NONE;
+
+ if (!IsCellEditable(m_LastDragOverCell))
+ return DROPEFFECT_NONE;
+ Valid = IsValid(m_LastDragOverCell)!=0;
+
+ }
+ else
+ {
+ Valid = m_LastDragOverCell.row>=0 && m_LastDragOverCell.row<GetFixedRowCount() && m_LastDragOverCell.col>=GetFixedColumnCount();
+ }
+
+ if (Valid)
+ {
+ UINT nState = GetItemState(m_LastDragOverCell.row, m_LastDragOverCell.col);
+ SetItemState(m_LastDragOverCell.row, m_LastDragOverCell.col,
+ nState | GVIS_DROPHILITED);
+ RedrawCell(m_LastDragOverCell);
+ }
+
+ // Return an appropraite value of DROPEFFECT so mouse cursor is set properly
+ if (dwKeyState & MK_CONTROL)
+ return DROPEFFECT_COPY;
+ else
+ return DROPEFFECT_MOVE;
+}
+
+// Something has just been dragged away from the grid
+void CGridCtrl::OnDragLeave()
+{
+ // Set the previously drop-highlighted cell as no longer drop-highlighted
+ if (IsValid(m_LastDragOverCell))
+ {
+ UINT nState = GetItemState(m_LastDragOverCell.row, m_LastDragOverCell.col);
+ SetItemState(m_LastDragOverCell.row, m_LastDragOverCell.col,
+ nState & ~GVIS_DROPHILITED);
+ RedrawCell(m_LastDragOverCell);
+ }
+}
+
+// Something has just been dropped onto the grid
+BOOL CGridCtrl::OnDrop(COleDataObject* pDataObject, DROPEFFECT /*dropEffect*/,
+ CPoint /* point */)
+{
+ m_MouseMode = MOUSE_NOTHING;
+ if(m_CurCol ==-1)
+ {
+ if (!m_bAllowDragAndDrop || (!IsCellEditable(m_LastDragOverCell) && !m_bDragRowMode))
+ return FALSE;
+ }
+
+ OnDragLeave();
+ if (m_CurCol>=0)
+ {
+ if(m_LastDragOverCell.col == m_CurCol || m_LastDragOverCell.row >= GetFixedRowCount())
+ return FALSE;
+ else
+ {
+ int New = m_arColOrder[m_CurCol];
+ m_arColOrder.erase(m_arColOrder.begin()+m_CurCol);
+ m_arColOrder.insert(m_arColOrder.begin()+m_LastDragOverCell.col, New);
+ m_CurCol=-1;
+ Invalidate();
+ return TRUE;
+ }
+ }
+ else
+ {
+ if(m_bDragRowMode)
+ {
+ Reorder(m_CurRow,m_LastDragOverCell.row);
+ Invalidate();
+ return TRUE;
+ }
+ else
+ return PasteTextToGrid(m_LastDragOverCell, pDataObject, FALSE);
+}
+}
+#endif
+
+#ifndef GRIDCONTROL_NO_CLIPBOARD
+void CGridCtrl::OnEditCut()
+{
+ if (!IsEditable())
+ return;
+
+ COleDataSource* pSource = CopyTextFromGrid();
+ if (!pSource)
+ return;
+
+ pSource->SetClipboard();
+ CutSelectedText();
+}
+
+void CGridCtrl::OnEditCopy()
+{
+ COleDataSource* pSource = CopyTextFromGrid();
+ if (!pSource)
+ return;
+
+ pSource->SetClipboard();
+}
+
+void CGridCtrl::OnEditPaste()
+{
+ if (!IsEditable())
+ return;
+
+ CCellRange cellRange = GetSelectedCellRange();
+
+ // Get the top-left selected cell, or the Focus cell, or the topleft (non-fixed) cell
+ CCellID cell;
+ if (cellRange.IsValid())
+ {
+ cell.row = cellRange.GetMinRow();
+ cell.col = cellRange.GetMinCol();
+ }
+ else
+ {
+ cell = GetFocusCell();
+ if (!IsValid(cell))
+ cell = GetTopleftNonFixedCell();
+ if (!IsValid(cell))
+ return;
+ }
+
+ // If a cell is being edited, then call it's edit window paste function.
+ if ( IsItemEditing(cell.row, cell.col) )
+ {
+ CGridCellBase* pCell = GetCell(cell.row, cell.col);
+// ASSERT(pCell);
+ if (!pCell) return;
+
+ CWnd* pEditWnd = pCell->GetEditWnd();
+ if ( pEditWnd && pEditWnd->IsKindOf(RUNTIME_CLASS(CEdit)) )
+ {
+ ((CEdit*)pEditWnd)->Paste();
+ return;
+ }
+ }
+
+ // Attach a COleDataObject to the clipboard and paste the data to the grid
+ COleDataObject obj;
+ if (obj.AttachClipboard())
+ PasteTextToGrid(cell, &obj);
+}
+#endif
+
+void CGridCtrl::OnEditSelectAll()
+{
+ SendMessageToParent(m_LeftClickDownCell.row, m_LeftClickDownCell.col, GVN_SELCHANGING);
+ SelectAllCells();
+ SendMessageToParent(m_idCurrentCell.row, m_idCurrentCell.col, GVN_SELCHANGED);
+}
+
+#ifndef GRIDCONTROL_NO_CLIPBOARD
+void CGridCtrl::OnUpdateEditCopy(CCmdUI* pCmdUI)
+{
+ pCmdUI->Enable(GetSelectedCount() > 0); // - Thomas Haase
+ //CCellRange Selection = GetSelectedCellRange();
+ //pCmdUI->Enable(Selection.Count() && IsValid(Selection));
+}
+
+void CGridCtrl::OnUpdateEditCut(CCmdUI* pCmdUI)
+{
+ pCmdUI->Enable(IsEditable() && GetSelectedCount() > 0); // - Thomas Haase
+ //CCellRange Selection = GetSelectedCellRange();
+ //pCmdUI->Enable(IsEditable() && Selection.Count() && IsValid(Selection));
+}
+
+void CGridCtrl::OnUpdateEditPaste(CCmdUI* pCmdUI)
+{
+ CCellID cell = GetFocusCell();
+
+ BOOL bCanPaste = IsValid(cell) && IsCellEditable(cell) &&
+ ::IsClipboardFormatAvailable(CF_TEXT);
+
+ pCmdUI->Enable(bCanPaste);
+}
+#endif
+
+void CGridCtrl::OnUpdateEditSelectAll(CCmdUI* pCmdUI)
+{
+ pCmdUI->Enable(m_bEnableSelection);
+}
+
+////////////////////////////////////////////////////////////////////////////////////////
+// hittest-like functions
+
+// TRUE if the mouse is over a row resize area
+BOOL CGridCtrl::MouseOverRowResizeArea(CPoint& point)
+{
+ if (point.x >= GetFixedColumnWidth())
+ return FALSE;
+
+ CCellID idCurrentCell = GetCellFromPt(point);
+ CPoint start;
+ if (!GetCellOrigin(idCurrentCell, &start))
+ return FALSE;
+
+ int endy = start.y + GetRowHeight(idCurrentCell.row);
+
+ if ((point.y - start.y < m_nResizeCaptureRange && idCurrentCell.row != 0) ||
+ endy - point.y < m_nResizeCaptureRange)
+ {
+ return TRUE;
+ }
+ else
+ return FALSE;
+}
+
+// TRUE if the mouse is over a column resize area. point is in Client coords
+BOOL CGridCtrl::MouseOverColumnResizeArea(CPoint& point)
+{
+ if (point.y >= GetFixedRowHeight())
+ return FALSE;
+
+ CCellID idCurrentCell = GetCellFromPt(point);
+ CPoint start;
+ if (!GetCellOrigin(idCurrentCell, &start))
+ return FALSE;
+
+ int endx = start.x + GetColumnWidth(idCurrentCell.col);
+
+ if ((point.x - start.x < m_nResizeCaptureRange && idCurrentCell.col != 0) ||
+ endx - point.x < m_nResizeCaptureRange)
+ {
+ return TRUE;
+ }
+ else
+ return FALSE;
+}
+
+// Get cell from point.
+// point - client coordinates
+// bAllowFixedCellCheck - if TRUE then fixed cells are checked
+CCellID CGridCtrl::GetCellFromPt(CPoint point, BOOL bAllowFixedCellCheck/* =TRUE*/, CCellID& cellOriginal/*= cellNull*/)
+{
+ CCellID cellID; // return value
+
+ CCellID idTopLeft = GetTopleftNonFixedCell();
+ if (!bAllowFixedCellCheck && !IsValid(idTopLeft))
+ return cellID;
+
+ // calculate column index
+ // LUC
+ int fixedColWidth = GetFixedColumnWidth(TRUE);
+ int nFixedCols = m_nFixedCols + m_nFreezedCols;
+
+ if (point.x < 0 || (!bAllowFixedCellCheck && point.x < fixedColWidth)) // not in window
+ cellID.col = -1;
+ else if (point.x < fixedColWidth) // in fixed col
+ {
+ int xpos = 0;
+ int col = 0;
+ while (col < nFixedCols)
+ {
+ xpos += GetColumnWidth(col);
+ if (xpos > point.x)
+ break;
+ col++;
+ }
+
+ cellID.col = col;
+ }
+ else // in non-fixed col
+ {
+ int xpos = fixedColWidth;
+ int col = idTopLeft.col; //m_nFixedCols;
+ while ( col < GetColumnCount())
+ {
+ xpos += GetColumnWidth(col);
+ if (xpos > point.x)
+ break;
+ col++;
+ }
+
+ if (col >= GetColumnCount())
+ cellID.col = -1;
+ else
+ cellID.col = col;
+ }
+
+ // calculate row index
+ // LUC
+ int fixedRowHeight = GetFixedRowHeight(TRUE);
+ if (point.y < 0 || (!bAllowFixedCellCheck && point.y < fixedRowHeight)) // not in window
+ cellID.row = -1;
+ else if (point.y < fixedRowHeight) // in fixed col
+ {
+ int ypos = 0;
+ int row = 0;
+ int nFixedRows = m_nFixedRows + m_nFreezedRows;
+ while (row < nFixedRows)
+ {
+ ypos += GetRowHeight(row);
+ if (ypos > point.y)
+ break;
+ row++;
+ }
+ cellID.row = row;
+ }
+ else
+ {
+ int ypos = fixedRowHeight;
+ int row = idTopLeft.row; //m_nFixedRows;
+ while ( row < GetRowCount() )
+ {
+ ypos += GetRowHeight(row);
+ if (ypos > point.y)
+ break;
+ row++;
+ }
+
+ if (row >= GetRowCount())
+ cellID.row = -1;
+ else
+ cellID.row = row;
+ }
+
+ // LUC
+ if(cellOriginal != cellNull)
+ {
+ cellOriginal = cellID;
+ }
+ GetTopLeftMergedCell(cellID.row, cellID.col, rectNull);
+
+ return cellID;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// CGridCtrl cellrange functions
+
+// Gets the first non-fixed cell ID
+CCellID CGridCtrl::GetTopleftNonFixedCell(BOOL bForceRecalculation /*=FALSE*/)
+{
+ // Used cached value if possible
+ if (m_idTopLeftCell.IsValid() && !bForceRecalculation)
+ return m_idTopLeftCell;
+
+ int nVertScroll = GetScrollPos(SB_VERT),
+ nHorzScroll = GetScrollPos(SB_HORZ);
+
+ // LUC
+ m_idTopLeftCell.col = m_nFixedCols + m_nFreezedCols;
+ int nRight = 0;
+ while (nRight < nHorzScroll && m_idTopLeftCell.col < (GetColumnCount()-1))
+ nRight += GetColumnWidth(m_idTopLeftCell.col++);
+
+ // LUC
+ m_idTopLeftCell.row = m_nFixedRows + m_nFreezedRows;
+ int nTop = 0;
+ while (nTop < nVertScroll && m_idTopLeftCell.row < (GetRowCount()-1))
+ nTop += GetRowHeight(m_idTopLeftCell.row++);
+
+
+ //TRACE2("TopLeft cell is row %d, col %d\n",m_idTopLeftCell.row, m_idTopLeftCell.col);
+ return m_idTopLeftCell;
+}
+
+
+
+
+
+// This gets even partially visible cells
+CCellRange CGridCtrl::GetVisibleNonFixedCellRange(LPRECT pRect /*=NULL*/,
+ BOOL bForceRecalculation /*=FALSE*/)
+{
+ int i;
+ CRect rect;
+ GetClientRect(rect);
+
+ CCellID idTopLeft = GetTopleftNonFixedCell(bForceRecalculation);
+
+ // calc bottom
+ // LUC
+ int bottom = GetFixedRowHeight();
+ //for (i = idTopLeft.row; i < GetRowCount(); i++)
+ for (i = m_nFixedRows; i < GetRowCount(); i++)
+ {
+ if(i == (m_nFixedRows+ m_nFreezedRows))
+ {
+ i = idTopLeft.row;
+ }
+ bottom += GetRowHeight(i);
+ if (bottom >= rect.bottom)
+ {
+ bottom = rect.bottom;
+ break;
+ }
+ }
+ int maxVisibleRow = min(i, GetRowCount() - 1);
+
+ // calc right
+ // LUC
+ int right = GetFixedColumnWidth();
+ //for (i = idTopLeft.col; i < GetColumnCount(); i++)
+ for (i = m_nFixedCols; i < GetColumnCount(); i++)
+ {
+ if(i == (m_nFixedCols + m_nFreezedCols))
+ {
+ i = idTopLeft.col;
+ }
+ right += GetColumnWidth(i);
+ if (right >= rect.right)
+ {
+ right = rect.right;
+ break;
+ }
+ }
+ int maxVisibleCol = min(i, GetColumnCount() - 1);
+ if (pRect)
+ {
+ pRect->left = pRect->top = 0;
+ pRect->right = right;
+ pRect->bottom = bottom;
+ }
+
+ // LUC
+ /*if(bIncludeFreezedCells)
+ {
+ if(m_nFreezedRows > 0)
+ {
+ idTopLeft.row = m_nFixedRows;
+ }
+ if(m_nFreezedCols > 0)
+ {
+ idTopLeft.col = m_nFixedCols;
+ }
+ }*/
+
+ if(!m_bExcludeFreezedRowsFromSelection)
+ {
+ if(m_nFreezedRows > 0)
+ {
+ idTopLeft.row = m_nFixedRows;
+ }
+
+ }
+ if(!m_bExcludeFreezedColsFromSelection)
+ {
+ if(m_nFreezedCols > 0)
+ {
+ idTopLeft.col = m_nFixedCols;
+ }
+ }
+
+ return CCellRange(idTopLeft.row, idTopLeft.col, maxVisibleRow, maxVisibleCol);
+}
+
+
+CCellRange CGridCtrl::GetVisibleFixedCellRange(LPRECT pRect /*=NULL*/,
+ BOOL bForceRecalculation /*=FALSE*/)
+{
+ int i;
+ CRect rect;
+ GetClientRect(rect);
+
+ CCellID idTopLeft = GetTopleftNonFixedCell(bForceRecalculation);
+
+ // calc bottom
+ // LUC
+ int bottom = GetFixedRowHeight(m_bExcludeFreezedRowsFromSelection);
+ for (i = idTopLeft.row; i < GetRowCount(); i++)
+ {
+ bottom += GetRowHeight(i);
+ if (bottom >= rect.bottom)
+ {
+ bottom = rect.bottom;
+ break;
+ }
+ }
+ int maxVisibleRow = min(i, GetRowCount() - 1);
+
+ // calc right
+ int right = 0;
+ for (i = 0; i < GetFixedColumnCount(m_bExcludeFreezedColsFromSelection); i++)
+ {
+ right += GetColumnWidth(i);
+ if (right >= rect.right)
+ {
+ right = rect.right;
+ break;
+ }
+ }
+ int maxVisibleCol = min(i, GetColumnCount() - 1);
+ if (pRect)
+ {
+ pRect->left = pRect->top = 0;
+ pRect->right = right;
+ pRect->bottom = bottom;
+ }
+
+ return CCellRange(idTopLeft.row, 0, maxVisibleRow, maxVisibleCol);
+}
+
+
+
+
+// used by ResetScrollBars() - This gets only fully visible cells
+CCellRange CGridCtrl::GetUnobstructedNonFixedCellRange(BOOL bForceRecalculation /*=FALSE*/)
+{
+ CRect rect;
+ GetClientRect(rect);
+
+ CCellID idTopLeft = GetTopleftNonFixedCell(bForceRecalculation);
+
+ // calc bottom
+ int i;
+ int bottom = GetFixedRowHeight();
+ for (i = idTopLeft.row; i < GetRowCount(); i++)
+ {
+ bottom += GetRowHeight(i);
+ if (bottom >= rect.bottom)
+ break;
+ }
+ int maxVisibleRow = min(i, GetRowCount() - 1);
+ if (maxVisibleRow > 0 && bottom > rect.bottom)
+ maxVisibleRow--;
+
+ // calc right
+ int right = GetFixedColumnWidth();
+ for (i = idTopLeft.col; i < GetColumnCount(); i++)
+ {
+ right += GetColumnWidth(i);
+ if (right >= rect.right)
+ break;
+ }
+ int maxVisibleCol = min(i, GetColumnCount() - 1);
+ if (maxVisibleCol > 0 && right > rect.right)
+ maxVisibleCol--;
+
+
+ return CCellRange(idTopLeft.row, idTopLeft.col, maxVisibleRow, maxVisibleCol);
+}
+
+// Returns the minimum bounding range of the current selection
+// If no selection, then the returned CCellRange will be invalid
+CCellRange CGridCtrl::GetSelectedCellRange() const
+{
+ CCellRange Selection(GetRowCount(), GetColumnCount(), -1,-1);
+
+ for (POSITION pos = m_SelectedCellMap.GetStartPosition(); pos != NULL; )
+ {
+ DWORD key;
+ CCellID cell;
+ m_SelectedCellMap.GetNextAssoc(pos, key, (CCellID&)cell);
+
+ Selection.SetMinRow( min(Selection.GetMinRow(), cell.row) );
+ Selection.SetMinCol( min(Selection.GetMinCol(), cell.col) );
+ Selection.SetMaxRow( __max(Selection.GetMaxRow(), cell.row) );
+ Selection.SetMaxCol( __max(Selection.GetMaxCol(), cell.col) );
+ }
+
+ return Selection;
+}
+
+// Returns ALL the cells in the grid
+CCellRange CGridCtrl::GetCellRange() const
+{
+ return CCellRange(0, 0, GetRowCount() - 1, GetColumnCount() - 1);
+}
+
+// Resets the selected cell range to the empty set.
+void CGridCtrl::ResetSelectedRange()
+{
+ m_PrevSelectedCellMap.RemoveAll();
+ SetSelectedRange(-1,-1,-1,-1);
+ SetFocusCell(-1,-1);
+}
+
+// Get/Set scroll position using 32 bit functions
+int CGridCtrl::GetScrollPos32(int nBar, BOOL bGetTrackPos /* = FALSE */)
+{
+ SCROLLINFO si;
+ si.cbSize = sizeof(SCROLLINFO);
+
+ if (bGetTrackPos)
+ {
+ if (GetScrollInfo(nBar, &si, SIF_TRACKPOS))
+ return si.nTrackPos;
+ }
+ else
+ {
+ if (GetScrollInfo(nBar, &si, SIF_POS))
+ return si.nPos;
+ }
+
+ return 0;
+}
+
+BOOL CGridCtrl::SetScrollPos32(int nBar, int nPos, BOOL bRedraw /* = TRUE */)
+{
+ m_idTopLeftCell.row = -1;
+
+ SCROLLINFO si;
+ si.cbSize = sizeof(SCROLLINFO);
+ si.fMask = SIF_POS;
+ si.nPos = nPos;
+ return SetScrollInfo(nBar, &si, bRedraw);
+}
+
+void CGridCtrl::EnableScrollBars(int nBar, BOOL bEnable /*=TRUE*/)
+{
+ if (bEnable)
+ {
+ if (!IsVisibleHScroll() && (nBar == SB_HORZ || nBar == SB_BOTH))
+ {
+ m_nBarState |= GVL_HORZ;
+ CWnd::EnableScrollBarCtrl(SB_HORZ, bEnable);
+ }
+
+ if (!IsVisibleVScroll() && (nBar == SB_VERT || nBar == SB_BOTH))
+ {
+ m_nBarState |= GVL_VERT;
+ CWnd::EnableScrollBarCtrl(SB_VERT, bEnable);
+ }
+ }
+ else
+ {
+ if ( IsVisibleHScroll() && (nBar == SB_HORZ || nBar == SB_BOTH))
+ {
+ m_nBarState &= ~GVL_HORZ;
+ CWnd::EnableScrollBarCtrl(SB_HORZ, bEnable);
+ }
+
+ if ( IsVisibleVScroll() && (nBar == SB_VERT || nBar == SB_BOTH))
+ {
+ m_nBarState &= ~GVL_VERT;
+ CWnd::EnableScrollBarCtrl(SB_VERT, bEnable);
+ }
+ }
+}
+
+// If resizing or cell counts/sizes change, call this - it'll fix up the scroll bars
+void CGridCtrl::ResetScrollBars()
+{
+ // Force a refresh.
+ m_idTopLeftCell.row = -1;
+
+ if (!m_bAllowDraw || !::IsWindow(GetSafeHwnd()))
+ return;
+
+ CRect rect;
+
+ // This would have caused OnSize event - Brian
+ //EnableScrollBars(SB_BOTH, FALSE);
+
+ GetClientRect(rect);
+
+ if (rect.left == rect.right || rect.top == rect.bottom)
+ return;
+
+ if (IsVisibleVScroll())
+ rect.right += GetSystemMetrics(SM_CXVSCROLL) + GetSystemMetrics(SM_CXBORDER);
+
+ if (IsVisibleHScroll())
+ rect.bottom += GetSystemMetrics(SM_CYHSCROLL) + GetSystemMetrics(SM_CYBORDER);
+
+ rect.left += GetFixedColumnWidth(TRUE);
+ rect.top += GetFixedRowHeight(TRUE);
+
+
+ if (rect.left >= rect.right || rect.top >= rect.bottom)
+ {
+ EnableScrollBarCtrl(SB_BOTH, FALSE);
+ return;
+ }
+
+ CRect VisibleRect(GetFixedColumnWidth(TRUE), GetFixedRowHeight(TRUE),
+ rect.right, rect.bottom);
+ CRect VirtualRect(GetFixedColumnWidth(TRUE), GetFixedRowHeight(TRUE),
+ GetVirtualWidth(), GetVirtualHeight());
+
+ // Removed to fix single row scrollbar problem (Pontus Goffe)
+ // CCellRange visibleCells = GetUnobstructedNonFixedCellRange();
+ // if (!IsValid(visibleCells)) return;
+
+ //TRACE(_T("Visible: %d x %d, Virtual %d x %d. H %d, V %d\n"),
+ // VisibleRect.Width(), VisibleRect.Height(),
+ // VirtualRect.Width(), VirtualRect.Height(),
+ // IsVisibleHScroll(), IsVisibleVScroll());
+
+ // If vertical scroll bar, horizontal space is reduced
+ if (VisibleRect.Height() < VirtualRect.Height())
+ VisibleRect.right -= ::GetSystemMetrics(SM_CXVSCROLL);
+ // If horz scroll bar, vert space is reduced
+ if (VisibleRect.Width() < VirtualRect.Width())
+ VisibleRect.bottom -= ::GetSystemMetrics(SM_CYHSCROLL);
+
+ // Recheck vertical scroll bar
+ //if (VisibleRect.Height() < VirtualRect.Height())
+ // VisibleRect.right -= ::GetSystemMetrics(SM_CXVSCROLL);
+
+ if (VisibleRect.Height() < VirtualRect.Height())
+ {
+ EnableScrollBars(SB_VERT, TRUE);
+ m_nVScrollMax = VirtualRect.Height() - 1;
+ }
+ else
+ {
+ EnableScrollBars(SB_VERT, FALSE);
+ m_nVScrollMax = 0;
+ }
+
+ if (VisibleRect.Width() < VirtualRect.Width())
+ {
+ EnableScrollBars(SB_HORZ, TRUE);
+ m_nHScrollMax = VirtualRect.Width() - 1;
+ }
+ else
+ {
+ EnableScrollBars(SB_HORZ, FALSE);
+ m_nHScrollMax = 0;
+ }
+
+// ASSERT(m_nVScrollMax < INT_MAX && m_nHScrollMax < INT_MAX); // This should be fine
+
+ /* Old code - CJM
+ SCROLLINFO si;
+ si.cbSize = sizeof(SCROLLINFO);
+ si.fMask = SIF_PAGE;
+ si.nPage = (m_nHScrollMax>0)? VisibleRect.Width() : 0;
+ SetScrollInfo(SB_HORZ, &si, FALSE);
+ si.nPage = (m_nVScrollMax>0)? VisibleRect.Height() : 0;
+ SetScrollInfo(SB_VERT, &si, FALSE);
+
+ SetScrollRange(SB_VERT, 0, m_nVScrollMax, TRUE);
+ SetScrollRange(SB_HORZ, 0, m_nHScrollMax, TRUE);
+ */
+
+ // New code - Paul Runstedler
+ SCROLLINFO si;
+ si.cbSize = sizeof(SCROLLINFO);
+ si.fMask = SIF_PAGE | SIF_RANGE;
+ si.nPage = (m_nHScrollMax>0)? VisibleRect.Width() : 0;
+ si.nMin = 0;
+ si.nMax = m_nHScrollMax;
+ SetScrollInfo(SB_HORZ, &si, TRUE);
+
+ si.fMask |= SIF_DISABLENOSCROLL;
+ si.nPage = (m_nVScrollMax>0)? VisibleRect.Height() : 0;
+ si.nMin = 0;
+ si.nMax = m_nVScrollMax;
+ SetScrollInfo(SB_VERT, &si, TRUE);
+}
+
+////////////////////////////////////////////////////////////////////////////////////
+// Row/Column position functions
+
+// returns the top left point of the cell. Returns FALSE if cell not visible.
+BOOL CGridCtrl::GetCellOrigin(int nRow, int nCol, LPPOINT p)
+{
+ int i;
+
+ if (!IsValid(nRow, nCol))
+ return FALSE;
+
+ CCellID idTopLeft;
+ int nFixedCols = m_nFixedCols + m_nFreezedCols;
+ int nFixedRows = m_nFixedRows + m_nFreezedRows;
+
+ // LUC
+ if (nCol >= nFixedCols || nRow >= nFixedRows)
+ idTopLeft = GetTopleftNonFixedCell();
+
+ if ((nRow >= nFixedRows && nRow < idTopLeft.row) ||
+ (nCol>= nFixedCols && nCol < idTopLeft.col))
+ return FALSE;
+
+ p->x = 0;
+ if (nCol < nFixedCols) // is a fixed column
+ for (i = 0; i < nCol; i++)
+ p->x += GetColumnWidth(i);
+ else
+ { // is a scrollable data column
+ for (i = 0; i < nFixedCols; i++)
+ p->x += GetColumnWidth(i);
+ for (i = idTopLeft.col; i < nCol; i++)
+ p->x += GetColumnWidth(i);
+ }
+
+ p->y = 0;
+ if (nRow < nFixedRows) // is a fixed row
+ for (i = 0; i < nRow; i++)
+ p->y += GetRowHeight(i);
+ else
+ { // is a scrollable data row
+ for (i = 0; i < nFixedRows; i++)
+ p->y += GetRowHeight(i);
+ for (i = idTopLeft.row; i < nRow; i++)
+ p->y += GetRowHeight(i);
+ }
+
+ return TRUE;
+}
+
+BOOL CGridCtrl::GetCellOrigin(const CCellID& cell, LPPOINT p)
+{
+ return GetCellOrigin(cell.row, cell.col, p);
+}
+
+// Returns the bounding box of the cell
+BOOL CGridCtrl::GetCellRect(const CCellID& cell, LPRECT pRect)
+{
+ return GetCellRect(cell.row, cell.col, pRect);
+}
+
+BOOL CGridCtrl::GetCellRect(int nRow, int nCol, LPRECT pRect)
+{
+ CPoint CellOrigin;
+ if (!GetCellOrigin(nRow, nCol, &CellOrigin))
+ return FALSE;
+
+ pRect->left = CellOrigin.x;
+ pRect->top = CellOrigin.y;
+ pRect->right = CellOrigin.x + GetColumnWidth(nCol)-1;
+ pRect->bottom = CellOrigin.y + GetRowHeight(nRow)-1;
+
+ //TRACE("Row %d, col %d: L %d, T %d, W %d, H %d: %d,%d - %d,%d\n",
+ // nRow,nCol, CellOrigin.x, CellOrigin.y, GetColumnWidth(nCol), GetRowHeight(nRow),
+ // pRect->left, pRect->top, pRect->right, pRect->bottom);
+
+ return TRUE;
+}
+
+BOOL CGridCtrl::GetTextRect(const CCellID& cell, LPRECT pRect)
+{
+ return GetTextRect(cell.row, cell.col, pRect);
+}
+
+BOOL CGridCtrl::GetTextRect(int nRow, int nCol, LPRECT pRect)
+{
+ CGridCellBase* pCell = GetCell( nRow, nCol);
+ if( pCell == NULL)
+ return FALSE;
+
+ if( !GetCellRect( nRow, nCol, pRect) )
+ return FALSE;
+
+ return pCell->GetTextRect( pRect);
+}
+
+BOOL CGridCtrl::SetCellMaskEditable( int nRow, int nCol, BOOL bEditable )
+{
+ if (nRow < 0 || nRow >= m_pCellEnable.size())
+ {
+ return FALSE;
+ }
+
+ if (nCol < 0 || nCol >= m_pCellEnable[nRow].size())
+ {
+ return FALSE;
+ }
+
+ m_pCellEnable[nRow][nCol].SetEnable(bEditable);
+
+ return TRUE;
+}
+
+BOOL CGridCtrl::isCellMaskEditable( int nRow, int nCol )
+{
+ if (nRow < 0 || nRow >= m_pCellEnable.size())
+ {
+ return FALSE;
+ }
+
+ if (nCol < 0 || nCol >= m_pCellEnable[nRow].size())
+ {
+ return FALSE;
+ }
+
+ return m_pCellEnable[nRow][nCol].isEnable();
+}
+
+BOOL CGridCtrl::isCellMaskActivated( int nRow, int nCol )
+{
+ if (nRow < 0 || nRow >= m_pCellEnable.size())
+ {
+ return FALSE;
+ }
+
+ if (nCol < 0 || nCol >= m_pCellEnable[nRow].size())
+ {
+ return FALSE;
+ }
+
+ return m_pCellEnable[nRow][nCol].isActivated();
+}
+
+// Returns the bounding box of a range of cells
+BOOL CGridCtrl::GetCellRangeRect(const CCellRange& cellRange, LPRECT lpRect)
+{
+ CPoint MinOrigin,MaxOrigin;
+
+ if (!GetCellOrigin(cellRange.GetMinRow(), cellRange.GetMinCol(), &MinOrigin))
+ return FALSE;
+ if (!GetCellOrigin(cellRange.GetMaxRow(), cellRange.GetMaxCol(), &MaxOrigin))
+ return FALSE;
+
+ lpRect->left = MinOrigin.x;
+ lpRect->top = MinOrigin.y;
+ lpRect->right = MaxOrigin.x + GetColumnWidth(cellRange.GetMaxCol()) - 1;
+ lpRect->bottom = MaxOrigin.y + GetRowHeight(cellRange.GetMaxRow()) - 1;
+
+ return TRUE;
+}
+
+////////////////////////////////////////////////////////////////////////////////////
+// Grid attribute functions
+
+LRESULT CGridCtrl::OnSetFont(WPARAM hFont, LPARAM /*lParam */)
+{
+ LRESULT result = Default();
+
+ // Get the logical font
+ LOGFONT lf;
+ if (!GetObject((HFONT) hFont, sizeof(LOGFONT), &lf))
+ return result;
+
+ m_cellDefault.SetFont(&lf);
+ m_cellFixedColDef.SetFont(&lf);
+ m_cellFixedRowDef.SetFont(&lf);
+ m_cellFixedRowColDef.SetFont(&lf);
+
+ Refresh();
+
+ return result;
+}
+
+LRESULT CGridCtrl::OnGetFont(WPARAM /*wParam*/, LPARAM /*lParam*/)
+{
+ //LOGFONT lf;
+ //m_cellDefault.GetFontObject()->GetLogFont(&lf);
+
+ return (LRESULT) m_cellDefault.GetFontObject()->GetSafeHandle();
+}
+
+#ifndef _WIN32_WCE_NO_CURSOR
+BOOL CGridCtrl::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
+{
+ if (nHitTest == HTCLIENT)
+ {
+ switch (m_MouseMode)
+ {
+ case MOUSE_OVER_COL_DIVIDE:
+ SetCursor(AfxGetApp()->LoadStandardCursor(IDC_SIZEWE));
+ break;
+ case MOUSE_OVER_ROW_DIVIDE:
+ SetCursor(AfxGetApp()->LoadStandardCursor(IDC_SIZENS));
+ break;
+#ifndef GRIDCONTROL_NO_DRAGDROP
+ case MOUSE_DRAGGING:
+ break;
+#endif
+ default:
+ if (!GetVirtualMode())
+ {
+ CPoint pt(GetMessagePos());
+ ScreenToClient(&pt);
+ CCellID cell = GetCellFromPt(pt);
+ if (IsValid(cell))
+ {
+ CGridCellBase* pCell = GetCell(cell.row, cell.col);
+ if (pCell)
+ return pCell->OnSetCursor();
+ }
+ }
+
+ SetCursor(AfxGetApp()->LoadStandardCursor(IDC_ARROW));
+ }
+ return TRUE;
+ }
+
+ return CWnd::OnSetCursor(pWnd, nHitTest, message);
+}
+#endif
+
+////////////////////////////////////////////////////////////////////////////////////
+// Row/Column count functions
+
+BOOL CGridCtrl::SetFixedRowCount(int nFixedRows)
+{
+ if (m_nFixedRows == nFixedRows)
+ return TRUE;
+
+// ASSERT(nFixedRows >= 0);
+
+ ResetSelectedRange();
+
+ // Force recalculation
+ m_idTopLeftCell.col = -1;
+
+ if (nFixedRows > GetRowCount())
+ if (!SetRowCount(nFixedRows))
+ return FALSE;
+
+ if (m_idCurrentCell.row < nFixedRows)
+ SetFocusCell(-1, - 1);
+
+ if (!GetVirtualMode())
+ {
+ if (nFixedRows > m_nFixedRows)
+ {
+ for (int i = m_nFixedRows; i < nFixedRows; i++)
+ for (int j = 0; j < GetColumnCount(); j++)
+ {
+ SetItemState(i, j, GetItemState(i, j) | GVIS_FIXED | GVIS_FIXEDROW);
+ SetItemBkColour(i, j, CLR_DEFAULT );
+ SetItemFgColour(i, j, CLR_DEFAULT );
+ }
+ }
+ else
+ {
+ for (int i = nFixedRows; i < m_nFixedRows; i++)
+ {
+ int j;
+ for (j = 0; j < GetFixedColumnCount(); j++)
+ SetItemState(i, j, GetItemState(i, j) & ~GVIS_FIXEDROW );
+
+ for (j = GetFixedColumnCount(); j < GetColumnCount(); j++)
+ {
+ SetItemState(i, j, GetItemState(i, j) & ~(GVIS_FIXED | GVIS_FIXEDROW) );
+ SetItemBkColour(i, j, CLR_DEFAULT );
+ SetItemFgColour(i, j, CLR_DEFAULT );
+ }
+ }
+ }
+ }
+
+ m_nFixedRows = nFixedRows;
+
+ Refresh();
+
+ return TRUE;
+}
+
+BOOL CGridCtrl::SetFixedColumnCount(int nFixedCols)
+{
+ if (m_nFixedCols == nFixedCols)
+ return TRUE;
+
+// ASSERT(nFixedCols >= 0);
+
+ if (nFixedCols > GetColumnCount())
+ if (!SetColumnCount(nFixedCols))
+ return FALSE;
+
+ if (m_idCurrentCell.col < nFixedCols)
+ SetFocusCell(-1, - 1);
+
+ ResetSelectedRange();
+
+ // Force recalculation
+ m_idTopLeftCell.col = -1;
+
+ if (!GetVirtualMode())
+ {
+ if (nFixedCols > m_nFixedCols)
+ {
+ for (int i = 0; i < GetRowCount(); i++)
+ for (int j = m_nFixedCols; j < nFixedCols; j++)
+ {
+ SetItemState(i, j, GetItemState(i, j) | GVIS_FIXED | GVIS_FIXEDCOL);
+ SetItemBkColour(i, j, CLR_DEFAULT );
+ SetItemFgColour(i, j, CLR_DEFAULT );
+ }
+ }
+ else
+ {
+ { // Scope limit i,j
+ for (int i = 0; i < GetFixedRowCount(); i++)
+ for (int j = nFixedCols; j < m_nFixedCols; j++)
+ SetItemState(i, j, GetItemState(i, j) & ~GVIS_FIXEDCOL );
+ }
+ {// Scope limit i,j
+ for (int i = GetFixedRowCount(); i < GetRowCount(); i++)
+ for (int j = nFixedCols; j < m_nFixedCols; j++)
+ {
+ SetItemState(i, j, GetItemState(i, j) & ~(GVIS_FIXED | GVIS_FIXEDCOL) );
+ SetItemBkColour(i, j, CLR_DEFAULT );
+ SetItemFgColour(i, j, CLR_DEFAULT );
+ }
+ }
+ }
+ }
+
+ m_nFixedCols = nFixedCols;
+
+ Refresh();
+
+ return TRUE;
+}
+
+BOOL CGridCtrl::SetRowCount(int nRows)
+{
+ BOOL bResult = TRUE;
+
+// ASSERT(nRows >= 0);
+ if (nRows == GetRowCount())
+ return bResult;
+
+ // Force recalculation
+ m_idTopLeftCell.col = -1;
+
+ if (nRows < m_nFixedRows)
+ m_nFixedRows = nRows;
+
+ if (m_idCurrentCell.row >= nRows)
+ SetFocusCell(-1, - 1);
+
+ int addedRows = nRows - GetRowCount();
+
+ // If we are about to lose rows, then we need to delete the GridCell objects
+ // in each column within each row
+ if (addedRows < 0)
+ {
+ if (!GetVirtualMode())
+ {
+ for (int row = nRows; row < m_nRows; row++)
+ {
+ // Delete cells
+ for (int col = 0; col < m_nCols; col++)
+ DestroyCell(row, col);
+
+ // Delete rows
+ GRID_ROW* pRow = m_RowData[row];
+ if (pRow)
+ delete pRow;
+ }
+ }
+ m_nRows = nRows;
+ }
+
+ TRY
+ {
+ m_arRowHeights.SetSize(nRows);
+
+ if (GetVirtualMode())
+ {
+ m_nRows = nRows;
+ if (addedRows > 0)
+ {
+ int startRow = nRows - addedRows;
+ for (int row = startRow; row < nRows; row++)
+ m_arRowHeights[row] = m_cellDefault.GetHeight();
+ }
+ ResetVirtualOrder();
+ }
+ else
+ {
+ // Change the number of rows.
+ m_RowData.SetSize(nRows);
+
+ // If we have just added rows, we need to construct new elements for each cell
+ // and set the default row height
+ if (addedRows > 0)
+ {
+ // initialize row heights and data
+ int startRow = nRows - addedRows;
+ for (int row = startRow; row < nRows; row++)
+ {
+ m_arRowHeights[row] = m_cellDefault.GetHeight();
+
+ m_RowData[row] = new GRID_ROW;
+ m_RowData[row]->SetSize(m_nCols);
+ for (int col = 0; col < m_nCols; col++)
+ {
+ GRID_ROW* pRow = m_RowData[row];
+ if (pRow && !GetVirtualMode())
+ pRow->SetAt(col, CreateCell(row, col));
+ }
+ m_nRows++;
+ }
+ }
+ }
+ }
+ CATCH (CMemoryException, e)
+ {
+ e->ReportError();
+ bResult = FALSE;
+ }
+ END_CATCH
+
+ SetModified();
+ ResetScrollBars();
+ Refresh();
+
+ return bResult;
+}
+
+BOOL CGridCtrl::SetColumnCount(int nCols)
+{
+ BOOL bResult = TRUE;
+
+// ASSERT(nCols >= 0);
+
+ if (nCols == GetColumnCount())
+ return bResult;
+
+ // Force recalculation
+ m_idTopLeftCell.col = -1;
+
+ if (nCols < m_nFixedCols)
+ m_nFixedCols = nCols;
+
+ if (m_idCurrentCell.col >= nCols)
+ SetFocusCell(-1, - 1);
+
+ int addedCols = nCols - GetColumnCount();
+
+ // If we are about to lose columns, then we need to delete the GridCell objects
+ // within each column
+ if (addedCols < 0 && !GetVirtualMode())
+ {
+ for (int row = 0; row < m_nRows; row++)
+ for (int col = nCols; col < GetColumnCount(); col++)
+ DestroyCell(row, col);
+ }
+
+ TRY
+ {
+ // Change the number of columns.
+ m_arColWidths.SetSize(nCols);
+
+ // Change the number of columns in each row.
+ if (!GetVirtualMode())
+ for (int i = 0; i < m_nRows; i++)
+ if (m_RowData[i])
+ m_RowData[i]->SetSize(nCols);
+
+ // If we have just added columns, we need to construct new elements for each cell
+ // and set the default column width
+ if (addedCols > 0)
+ {
+ int row, col;
+
+ // initialized column widths
+ int startCol = nCols - addedCols;
+ for (col = startCol; col < nCols; col++)
+ m_arColWidths[col] = m_cellFixedColDef.GetWidth();
+
+ // initialise column data
+ if (!GetVirtualMode())
+ {
+ for (row = 0; row < m_nRows; row++)
+ for (col = startCol; col < nCols; col++)
+ {
+ GRID_ROW* pRow = m_RowData[row];
+ if (pRow)
+ pRow->SetAt(col, CreateCell(row, col));
+ }
+ }
+ }
+ // else // check for selected cell ranges
+ // ResetSelectedRange();
+ }
+ CATCH (CMemoryException, e)
+ {
+ e->ReportError();
+ bResult = FALSE;
+ }
+ END_CATCH
+
+ m_arColOrder.resize(nCols); // Reset Column Order
+ for (int i = 0; i < nCols; i++)
+ {
+ m_arColOrder[i] = i;
+ }
+
+ m_nCols = nCols;
+
+ SetModified();
+ ResetScrollBars();
+ Refresh();
+
+ return bResult;
+}
+
+BOOL CGridCtrl::UpdateCellEditableMask()
+{
+ if (m_nRows != m_pCellEnable.size())
+ {
+ m_pCellEnable.resize(m_nRows);
+ }
+
+ for (int i = 0; i<m_nRows; i++)
+ {
+ if (m_nCols != m_pCellEnable[i].size())
+ {
+ m_pCellEnable[i].resize(m_nCols);
+ }
+ }
+
+ return TRUE;
+}
+
+// Insert a column at a given position, or add to end of columns (if nColumn = -1)
+int CGridCtrl::InsertColumn(LPCTSTR strHeading,
+ UINT nFormat /* = DT_CENTER|DT_VCENTER|DT_SINGLELINE */,
+ int nColumn /* = -1 */)
+{
+// ASSERT(!m_AllowReorderColumn); // function not implemented in case of m_AllowReorderColumn option
+ if (nColumn >= 0 && nColumn < m_nFixedCols)
+ {
+
+ // TODO: Fix it so column insertion works for in the fixed column area
+// ASSERT(FALSE);
+ return -1;
+ }
+
+ // If the insertion is for a specific column, check it's within range.
+ if (nColumn >= 0 && nColumn > GetColumnCount())
+ return -1;
+
+ // Force recalculation
+ m_idTopLeftCell.col = -1;
+
+ ResetSelectedRange();
+
+ // Gotta be able to at least _see_ some of the column.
+ if (m_nRows < 1)
+ SetRowCount(1);
+
+ // Allow the user to insert after the last of the columns, but process it as a
+ // "-1" column, meaning it gets flaged as being the last column, and not a regular
+ // "insert" routine.
+ if (nColumn == GetColumnCount())
+ nColumn = -1;
+
+ TRY
+ {
+ if (nColumn < 0)
+ {
+ nColumn = m_nCols;
+ m_arColWidths.Add(0);
+ if (!GetVirtualMode())
+ {
+ for (int row = 0; row < m_nRows; row++)
+ {
+ GRID_ROW* pRow = m_RowData[row];
+ if (!pRow)
+ return -1;
+ pRow->Add(CreateCell(row, nColumn));
+ }
+ }
+ }
+ else
+ {
+ m_arColWidths.InsertAt(nColumn, (UINT)0);
+ if (!GetVirtualMode())
+ {
+ for (int row = 0; row < m_nRows; row++)
+ {
+ GRID_ROW* pRow = m_RowData[row];
+ if (!pRow)
+ return -1;
+ pRow->InsertAt(nColumn, CreateCell(row, nColumn));
+ }
+ }
+ }
+ }
+ CATCH (CMemoryException, e)
+ {
+ e->ReportError();
+ return -1;
+ }
+ END_CATCH
+
+ m_nCols++;
+
+ // Initialise column data
+ SetItemText(0, nColumn, strHeading);
+ for (int row = 0; row < m_nRows; row++)
+ SetItemFormat(row, nColumn, nFormat);
+
+ // initialized column width
+ m_arColWidths[nColumn] = GetTextExtent(0, nColumn, strHeading).cx;
+
+ if (m_idCurrentCell.col != -1 && nColumn < m_idCurrentCell.col)
+ m_idCurrentCell.col++;
+
+ ResetScrollBars();
+
+ SetModified();
+
+ return nColumn;
+}
+
+// Insert a row at a given position, or add to end of rows (if nRow = -1)
+int CGridCtrl::InsertRow(LPCTSTR strHeading, int nRow /* = -1 */)
+{
+ if (nRow >= 0 && nRow < m_nFixedRows)
+ {
+ // TODO: Fix it so column insertion works for in the fixed row area
+// ASSERT(FALSE);
+ return -1;
+ }
+
+ // If the insertion is for a specific row, check it's within range.
+ if (nRow >= 0 && nRow >= GetRowCount())
+ return -1;
+
+ // Force recalculation
+ m_idTopLeftCell.col = -1;
+
+ ResetSelectedRange();
+
+ // Gotta be able to at least _see_ some of the row.
+ if (m_nCols < 1)
+ SetColumnCount(1);
+
+ TRY
+ {
+ // Adding a row to the bottom
+ if (nRow < 0)
+ {
+ nRow = m_nRows;
+ m_arRowHeights.Add(0);
+ if (!GetVirtualMode())
+ m_RowData.Add(new GRID_ROW);
+ else
+ m_arRowOrder.push_back(m_nRows);
+
+ }
+ else
+ {
+ m_arRowHeights.InsertAt(nRow, (UINT)0);
+ if (!GetVirtualMode())
+ m_RowData.InsertAt(nRow, new GRID_ROW);
+ else
+ {
+ ResetVirtualOrder();
+ }
+ }
+
+ if (!GetVirtualMode())
+ m_RowData[nRow]->SetSize(m_nCols);
+ }
+ CATCH (CMemoryException, e)
+ {
+ e->ReportError();
+ return -1;
+ }
+ END_CATCH
+
+ m_nRows++;
+
+ // Initialise cell data
+ if (!GetVirtualMode())
+ {
+ for (int col = 0; col < m_nCols; col++)
+ {
+ GRID_ROW* pRow = m_RowData[nRow];
+ if (!pRow)
+ return -1;
+ pRow->SetAt(col, CreateCell(nRow, col));
+ }
+ }
+
+ // Set row title
+ SetItemText(nRow, 0, strHeading);
+
+ // initialized row height
+ if (strHeading && strHeading[0])
+ m_arRowHeights[nRow] = GetTextExtent(nRow, 0, strHeading).cy;
+ else
+ m_arRowHeights[nRow] = m_cellFixedRowDef.GetHeight();
+
+ if (m_idCurrentCell.row != -1 && nRow < m_idCurrentCell.row)
+ m_idCurrentCell.row++;
+
+ ResetScrollBars();
+
+ SetModified();
+
+ return nRow;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Cell creation stuff
+
+BOOL CGridCtrl::SetCellType(int nRow, int nCol, CRuntimeClass* pRuntimeClass)
+{
+ if (GetVirtualMode())
+ return FALSE;
+
+// ASSERT(IsValid(nRow, nCol));
+ if (!IsValid(nRow, nCol))
+ return FALSE;
+
+ if (!pRuntimeClass->IsDerivedFrom(RUNTIME_CLASS(CGridCellBase)))
+ {
+// ASSERT( FALSE);
+ return FALSE;
+ }
+
+ CGridCellBase* pNewCell = (CGridCellBase*) pRuntimeClass->CreateObject();
+
+ CGridCellBase* pCurrCell = GetCell(nRow, nCol);
+ if (pCurrCell)
+ *pNewCell = *pCurrCell;
+
+ SetCell(nRow, nCol, pNewCell);
+ delete pCurrCell;
+
+ return TRUE;
+}
+
+BOOL CGridCtrl::SetDefaultCellType( CRuntimeClass* pRuntimeClass)
+{
+// ASSERT( pRuntimeClass != NULL );
+ if (!pRuntimeClass->IsDerivedFrom(RUNTIME_CLASS(CGridCellBase)))
+ {
+// ASSERT( FALSE);
+ return FALSE;
+ }
+ m_pRtcDefault = pRuntimeClass;
+ return TRUE;
+}
+
+// Creates a new grid cell and performs any necessary initialisation
+/*virtual*/ CGridCellBase* CGridCtrl::CreateCell(int nRow, int nCol)
+{
+// ASSERT(!GetVirtualMode());
+
+ if (!m_pRtcDefault || !m_pRtcDefault->IsDerivedFrom(RUNTIME_CLASS(CGridCellBase)))
+ {
+// ASSERT( FALSE);
+ return NULL;
+ }
+ CGridCellBase* pCell = (CGridCellBase*) m_pRtcDefault->CreateObject();
+ if (!pCell)
+ return NULL;
+
+ pCell->SetGrid(this);
+ pCell->SetCoords(nRow, nCol);
+
+ if (nCol < m_nFixedCols)
+ pCell->SetState(pCell->GetState() | GVIS_FIXED | GVIS_FIXEDCOL);
+ if (nRow < m_nFixedRows)
+ pCell->SetState(pCell->GetState() | GVIS_FIXED | GVIS_FIXEDROW);
+
+ pCell->SetFormat(pCell->GetDefaultCell()->GetFormat());
+
+ return pCell;
+}
+
+// Performs any cell cleanup necessary to maintain grid integrity
+/*virtual*/ void CGridCtrl::DestroyCell(int nRow, int nCol)
+{
+ // Should NEVER get here in virtual mode.
+// ASSERT(!GetVirtualMode());
+
+ // Set the cells state to 0. If the cell is selected, this
+ // will remove the cell from the selected list.
+ SetItemState(nRow, nCol, 0);
+
+ delete GetCell(nRow, nCol);
+}
+
+BOOL CGridCtrl::DeleteColumn(int nColumn)
+{
+ if (nColumn < 0 || nColumn >= GetColumnCount())
+ return FALSE;
+
+ ResetSelectedRange();
+
+ if (!GetVirtualMode())
+ {
+ for (int row = 0; row < GetRowCount(); row++)
+ {
+ GRID_ROW* pRow = m_RowData[row];
+ if (!pRow)
+ return FALSE;
+
+ DestroyCell(row, nColumn);
+
+ pRow->RemoveAt(nColumn);
+ }
+ }
+ m_arColWidths.RemoveAt(nColumn);
+ m_nCols--;
+ if (nColumn < m_nFixedCols)
+ m_nFixedCols--;
+
+ if (nColumn == m_idCurrentCell.col)
+ m_idCurrentCell.row = m_idCurrentCell.col = -1;
+ else if (nColumn < m_idCurrentCell.col)
+ m_idCurrentCell.col--;
+
+ ResetScrollBars();
+
+ SetModified();
+
+ return TRUE;
+}
+
+
+void CGridCtrl::AddSubVirtualRow(int Num, int Nb)
+{
+// ASSERT(Nb == -1 || Nb ==1); // only these vlaues are implemented now
+ if(!GetVirtualMode()) return;
+ for(int ind = 0; ind<m_nRows ; ind++)
+ if(m_arRowOrder[ind]>Num) m_arRowOrder[ind]+=Nb;
+ if(Nb>0)
+ m_arRowOrder.insert(m_arRowOrder.begin()+Num,Num);
+ else
+ m_arRowOrder.erase(m_arRowOrder.begin()+Num);
+}
+
+
+BOOL CGridCtrl::DeleteRow(int nRow)
+{
+ if (nRow < 0 || nRow >= GetRowCount())
+ return FALSE;
+
+ ResetSelectedRange();
+
+ if (!GetVirtualMode())
+ {
+ GRID_ROW* pRow = m_RowData[nRow];
+ if (!pRow)
+ return FALSE;
+
+ for (int col = 0; col < GetColumnCount(); col++)
+ DestroyCell(nRow, col);
+
+ delete pRow;
+ m_RowData.RemoveAt(nRow);
+ }
+ else
+ AddSubVirtualRow(nRow,-1);
+
+ m_arRowHeights.RemoveAt(nRow);
+
+ m_nRows--;
+ if (nRow < m_nFixedRows)
+ m_nFixedRows--;
+
+ if (nRow == m_idCurrentCell.row)
+ m_idCurrentCell.row = m_idCurrentCell.col = -1;
+ else if (nRow < m_idCurrentCell.row)
+ m_idCurrentCell.row--;
+
+ ResetScrollBars();
+
+ SetModified();
+
+ return TRUE;
+}
+
+// Handy function that removes all non-fixed rows
+BOOL CGridCtrl::DeleteNonFixedRows()
+{
+ ResetSelectedRange();
+ int nFixed = GetFixedRowCount();
+ int nCount = GetRowCount();
+ if (GetVirtualMode())
+ {
+ if(nCount != nFixed)
+ {
+ SetRowCount(nFixed);
+ m_arRowOrder.resize(nFixed);
+ m_arRowHeights.SetSize(nFixed);
+ m_idCurrentCell.row = m_idCurrentCell.col = -1;
+ ResetScrollBars();
+ SetModified();
+ }
+ }
+ else
+ {
+ // Delete all data rows
+ for (int nRow = nCount; nRow >= nFixed; nRow--)
+ DeleteRow(nRow);
+ }
+ return TRUE;
+}
+
+// Removes all rows, columns and data from the grid.
+BOOL CGridCtrl::DeleteAllItems()
+{
+ ResetSelectedRange();
+
+ m_arColWidths.RemoveAll();
+ m_arRowHeights.RemoveAll();
+
+ // Delete all cells in the grid
+ if (!GetVirtualMode())
+ {
+ for (int row = 0; row < m_nRows; row++)
+ {
+ for (int col = 0; col < m_nCols; col++)
+ DestroyCell(row, col);
+
+ GRID_ROW* pRow = m_RowData[row];
+ delete pRow;
+ }
+
+ // Remove all rows
+ m_RowData.RemoveAll();
+ }
+ else
+ m_arRowOrder.clear();
+
+
+ m_idCurrentCell.row = m_idCurrentCell.col = -1;
+ m_nRows = m_nFixedRows = m_nCols = m_nFixedCols = 0;
+
+ ResetScrollBars();
+
+ SetModified();
+
+ return TRUE;
+}
+
+void CGridCtrl::AutoFill()
+{
+ if (!::IsWindow(m_hWnd))
+ return;
+
+ CRect rect;
+ GetClientRect(rect);
+
+ SetColumnCount(rect.Width() / m_cellDefault.GetWidth() + 1);
+ SetRowCount(rect.Height() / m_cellDefault.GetHeight() + 1);
+ SetFixedRowCount(1);
+ SetFixedColumnCount(1);
+ ExpandToFit();
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// CGridCtrl data functions
+
+// Set CListCtrl::GetNextItem for details
+CCellID CGridCtrl::GetNextItem(CCellID& cell, int nFlags) const
+{
+ if ((nFlags & GVNI_ALL) == GVNI_ALL)
+ { // GVNI_ALL Search whole Grid beginning from cell
+ // First row (cell.row) -- ONLY Columns to the right of cell
+ // following rows -- ALL Columns
+ int row = cell.row , col = cell.col + 1;
+ if (row <= 0)
+ row = GetFixedRowCount();
+ for (; row < GetRowCount(); row++)
+ {
+ if (col <= 0)
+ col = GetFixedColumnCount();
+ for (; col < GetColumnCount(); col++)
+ {
+ int nState = GetItemState(row, col);
+ if ((nFlags & GVNI_DROPHILITED && nState & GVIS_DROPHILITED) ||
+ (nFlags & GVNI_FOCUSED && nState & GVIS_FOCUSED) ||
+ (nFlags & GVNI_SELECTED && nState & GVIS_SELECTED) ||
+ (nFlags & GVNI_READONLY && nState & GVIS_READONLY) ||
+ (nFlags & GVNI_FIXED && nState & GVIS_FIXED) ||
+ (nFlags & GVNI_MODIFIED && nState & GVIS_MODIFIED))
+ return CCellID(row, col);
+ }
+ // go to First Column
+ col = GetFixedColumnCount();
+ }
+ }
+ else if ((nFlags & GVNI_BELOW) == GVNI_BELOW &&
+ (nFlags & GVNI_TORIGHT) == GVNI_TORIGHT)
+ { // GVNI_AREA Search Grid beginning from cell to Lower-Right of Grid
+ // Only rows starting with cell.row and below
+ // All rows -- ONLY Columns to the right of cell
+ int row = cell.row;
+ if (row <= 0)
+ row = GetFixedRowCount();
+ for (; row < GetRowCount(); row++)
+ {
+ int col = cell.col + 1;
+ if (col <= 0)
+ col = GetFixedColumnCount();
+ for (; col < GetColumnCount(); col++)
+ {
+ int nState = GetItemState(row, col);
+ if ((nFlags & GVNI_DROPHILITED && nState & GVIS_DROPHILITED) ||
+ (nFlags & GVNI_FOCUSED && nState & GVIS_FOCUSED) ||
+ (nFlags & GVNI_SELECTED && nState & GVIS_SELECTED) ||
+ (nFlags & GVNI_READONLY && nState & GVIS_READONLY) ||
+ (nFlags & GVNI_FIXED && nState & GVIS_FIXED) ||
+ (nFlags & GVNI_MODIFIED && nState & GVIS_MODIFIED))
+ return CCellID(row, col);
+ }
+ }
+ }
+ else if ((nFlags & GVNI_ABOVE) == GVNI_ABOVE)
+ {
+ for (int row = cell.row - 1; row >= GetFixedRowCount(); row--)
+ {
+ int nState = GetItemState(row, cell.col);
+ if ((nFlags & GVNI_DROPHILITED && nState & GVIS_DROPHILITED) ||
+ (nFlags & GVNI_FOCUSED && nState & GVIS_FOCUSED) ||
+ (nFlags & GVNI_SELECTED && nState & GVIS_SELECTED) ||
+ (nFlags & GVNI_READONLY && nState & GVIS_READONLY) ||
+ (nFlags & GVNI_FIXED && nState & GVIS_FIXED) ||
+ (nFlags & GVNI_MODIFIED && nState & GVIS_MODIFIED))
+ return CCellID(row, cell.col);
+ }
+ }
+ else if ((nFlags & GVNI_BELOW) == GVNI_BELOW)
+ {
+ for (int row = cell.row + 1; row < GetRowCount(); row++)
+ {
+ int nState = GetItemState(row, cell.col);
+ if ((nFlags & GVNI_DROPHILITED && nState & GVIS_DROPHILITED) ||
+ (nFlags & GVNI_FOCUSED && nState & GVIS_FOCUSED) ||
+ (nFlags & GVNI_SELECTED && nState & GVIS_SELECTED) ||
+ (nFlags & GVNI_READONLY && nState & GVIS_READONLY) ||
+ (nFlags & GVNI_FIXED && nState & GVIS_FIXED) ||
+ (nFlags & GVNI_MODIFIED && nState & GVIS_MODIFIED))
+ return CCellID(row, cell.col);
+ }
+ }
+ else if ((nFlags & GVNI_TOLEFT) == GVNI_TOLEFT)
+ {
+ for (int col = cell.col - 1; col >= GetFixedColumnCount(); col--)
+ {
+ int nState = GetItemState(cell.row, col);
+ if ((nFlags & GVNI_DROPHILITED && nState & GVIS_DROPHILITED) ||
+ (nFlags & GVNI_FOCUSED && nState & GVIS_FOCUSED) ||
+ (nFlags & GVNI_SELECTED && nState & GVIS_SELECTED) ||
+ (nFlags & GVNI_READONLY && nState & GVIS_READONLY) ||
+ (nFlags & GVNI_FIXED && nState & GVIS_FIXED) ||
+ (nFlags & GVNI_MODIFIED && nState & GVIS_MODIFIED))
+ return CCellID(cell.row, col);
+ }
+ }
+ else if ((nFlags & GVNI_TORIGHT) == GVNI_TORIGHT)
+ {
+ for (int col = cell.col + 1; col < GetColumnCount(); col++)
+ {
+ int nState = GetItemState(cell.row, col);
+ if ((nFlags & GVNI_DROPHILITED && nState & GVIS_DROPHILITED) ||
+ (nFlags & GVNI_FOCUSED && nState & GVIS_FOCUSED) ||
+ (nFlags & GVNI_SELECTED && nState & GVIS_SELECTED) ||
+ (nFlags & GVNI_READONLY && nState & GVIS_READONLY) ||
+ (nFlags & GVNI_FIXED && nState & GVIS_FIXED) ||
+ (nFlags & GVNI_MODIFIED && nState & GVIS_MODIFIED))
+ return CCellID(cell.row, col);
+ }
+ }
+
+ return CCellID(-1, -1);
+}
+
+// Sorts on a given column using the cell text
+BOOL CGridCtrl::SortTextItems(int nCol, BOOL bAscending, LPARAM data /* = 0 */)
+{
+ return CGridCtrl::SortItems(pfnCellTextCompare, nCol, bAscending, data);
+}
+
+void CGridCtrl::SetCompareFunction(PFNLVCOMPARE pfnCompare)
+{
+ m_pfnCompare = pfnCompare;
+}
+
+// Sorts on a given column using the cell text and using the specified comparison
+// function
+BOOL CGridCtrl::SortItems(int nCol, BOOL bAscending, LPARAM data /* = 0 */)
+{
+ SetSortColumn(nCol);
+ SetSortAscending(bAscending);
+ ResetSelectedRange();
+ SetFocusCell(-1, - 1);
+
+ if (m_pfnCompare == NULL)
+ return CGridCtrl::SortItems(pfnCellTextCompare, nCol, bAscending, data);
+ else
+ return CGridCtrl::SortItems(m_pfnCompare, nCol, bAscending, data);
+}
+
+// Sorts on a given column using the supplied compare function (see CListCtrl::SortItems)
+BOOL CGridCtrl::SortItems(PFNLVCOMPARE pfnCompare, int nCol, BOOL bAscending,
+ LPARAM data /* = 0 */)
+{
+ SetSortColumn(nCol);
+ SetSortAscending(bAscending);
+ ResetSelectedRange();
+ SetFocusCell(-1, -1);
+ return SortItems(pfnCompare, nCol, bAscending, data, GetFixedRowCount(), -1);
+}
+
+int CALLBACK CGridCtrl::pfnCellTextCompare(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
+{
+ UNUSED_ALWAYS(lParamSort);
+
+ CGridCellBase* pCell1 = (CGridCellBase*) lParam1;
+ CGridCellBase* pCell2 = (CGridCellBase*) lParam2;
+ if (!pCell1 || !pCell2) return 0;
+
+ return _tcscmp(pCell1->GetText(), pCell2->GetText());
+}
+
+int CALLBACK CGridCtrl::pfnCellNumericCompare(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
+{
+ UNUSED_ALWAYS(lParamSort);
+
+ CGridCellBase* pCell1 = (CGridCellBase*) lParam1;
+ CGridCellBase* pCell2 = (CGridCellBase*) lParam2;
+ if (!pCell1 || !pCell2) return 0;
+
+ int nValue1 = _ttol(pCell1->GetText());
+ int nValue2 = _ttol(pCell2->GetText());
+
+ if (nValue1 < nValue2)
+ return -1;
+ else if (nValue1 == nValue2)
+ return 0;
+ else
+ return 1;
+}
+
+
+CGridCtrl * CGridCtrl::m_This;
+// private recursive sort implementation
+bool CGridCtrl::NotVirtualCompare(int c1, int c2)
+{
+ return ! CGridCtrl::m_This->m_pfnVirtualCompare(c1, c2);
+}
+BOOL CGridCtrl::SortItems(PFNLVCOMPARE pfnCompare, int nCol, BOOL bAscending, LPARAM data,
+ int low, int high)
+{
+ if (nCol >= GetColumnCount())
+ return FALSE;
+
+ if (high == -1)
+ high = GetRowCount() - 1;
+
+ int lo = low;
+ int hi = high;
+
+ if (hi <= lo)
+ return FALSE;
+
+ if (GetVirtualMode())
+ {
+// ASSERT(m_pfnVirtualCompare);
+ m_CurCol = m_arColOrder[nCol];
+ m_This = this;
+ std::stable_sort(m_arRowOrder.begin() + m_nFixedRows, m_arRowOrder.end(),
+ bAscending ? m_pfnVirtualCompare : NotVirtualCompare);
+ return TRUE;
+ }
+
+
+ //LPARAM midItem = GetItemData((lo + hi)/2, nCol);
+ LPARAM pMidCell = (LPARAM) GetCell((lo + hi)/2, nCol);
+
+ // loop through the list until indices cross
+ while (lo <= hi)
+ {
+ // Find the first element that is greater than or equal to the partition
+ // element starting from the left Index.
+ if (bAscending)
+ while (lo < high && pfnCompare( (LPARAM)GetCell(lo, nCol), (LPARAM) pMidCell, data) < 0)
+ ++lo;
+ else
+ while (lo < high && pfnCompare((LPARAM)GetCell(lo, nCol), pMidCell, data) > 0)
+ ++lo;
+
+ // Find an element that is smaller than or equal to the partition
+ // element starting from the right Index.
+ if (bAscending)
+ while (hi > low && pfnCompare((LPARAM)GetCell(hi, nCol), pMidCell, data) > 0)
+ --hi;
+ else
+ while (hi > low && pfnCompare((LPARAM)GetCell(hi, nCol), pMidCell, data) < 0)
+ --hi;
+
+ // If the indexes have not crossed, swap if the items are not equal
+ if (lo <= hi)
+ {
+ // swap only if the items are not equal
+ if (pfnCompare((LPARAM)GetCell(lo, nCol), (LPARAM)GetCell(hi, nCol), data) != 0)
+ {
+ for (int col = 0; col < GetColumnCount(); col++)
+ {
+ CGridCellBase *pCell = GetCell(lo, col);
+ SetCell(lo, col, GetCell(hi, col));
+ SetCell(hi, col, pCell);
+ }
+ UINT nRowHeight = m_arRowHeights[lo];
+ m_arRowHeights[lo] = m_arRowHeights[hi];
+ m_arRowHeights[hi] = nRowHeight;
+ }
+
+ ++lo;
+ --hi;
+ }
+ }
+
+ // If the right index has not reached the left side of array
+ // must now sort the left partition.
+ if (low < hi)
+ SortItems(pfnCompare, nCol, bAscending, data, low, hi);
+
+ // If the left index has not reached the right side of array
+ // must now sort the right partition.
+ if (lo < high)
+ SortItems(pfnCompare, nCol, bAscending, data, lo, high);
+
+ return TRUE;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// CGridCtrl data functions
+
+BOOL CGridCtrl::SetItem(const GV_ITEM* pItem)
+{
+ if (!pItem || GetVirtualMode())
+ return FALSE;
+
+ CGridCellBase* pCell = GetCell(pItem->row, pItem->col);
+ if (!pCell)
+ return FALSE;
+
+ SetModified(TRUE, pItem->row, pItem->col);
+
+ if (pItem->mask & GVIF_TEXT)
+ pCell->SetText(pItem->strText);
+ if (pItem->mask & GVIF_PARAM)
+ pCell->SetData(pItem->lParam);
+ if (pItem->mask & GVIF_IMAGE)
+ pCell->SetImage(pItem->iImage);
+ if (pItem->mask & GVIF_STATE)
+ SetItemState(pItem->row, pItem->col, pItem->nState);
+ if (pItem->mask & GVIF_FORMAT)
+ pCell->SetFormat(pItem->nFormat);
+ if (pItem->mask & GVIF_BKCLR)
+ pCell->SetBackClr(pItem->crBkClr);
+ if (pItem->mask & GVIF_FGCLR)
+ pCell->SetTextClr(pItem->crFgClr);
+ if (pItem->mask & GVIF_FONT)
+ pCell->SetFont(&(pItem->lfFont));
+ if( pItem->mask & GVIF_MARGIN)
+ pCell->SetMargin( pItem->nMargin);
+
+ return TRUE;
+}
+
+BOOL CGridCtrl::GetItem(GV_ITEM* pItem)
+{
+ if (!pItem)
+ return FALSE;
+ CGridCellBase* pCell = GetCell(pItem->row, pItem->col);
+ if (!pCell)
+ return FALSE;
+
+ if (pItem->mask & GVIF_TEXT)
+ pItem->strText = GetItemText(pItem->row, pItem->col);
+ if (pItem->mask & GVIF_PARAM)
+ pItem->lParam = pCell->GetData();;
+ if (pItem->mask & GVIF_IMAGE)
+ pItem->iImage = pCell->GetImage();
+ if (pItem->mask & GVIF_STATE)
+ pItem->nState = pCell->GetState();
+ if (pItem->mask & GVIF_FORMAT)
+ pItem->nFormat = pCell->GetFormat();
+ if (pItem->mask & GVIF_BKCLR)
+ pItem->crBkClr = pCell->GetBackClr();
+ if (pItem->mask & GVIF_FGCLR)
+ pItem->crFgClr = pCell->GetTextClr();
+ if (pItem->mask & GVIF_FONT)
+ memcpy(&(pItem->lfFont), pCell->GetFont(), sizeof(LOGFONT));
+ if( pItem->mask & GVIF_MARGIN)
+ pItem->nMargin = pCell->GetMargin();
+
+ return TRUE;
+}
+
+BOOL CGridCtrl::SetItemText(int nRow, int nCol, LPCTSTR str)
+{
+ if (GetVirtualMode())
+ return FALSE;
+
+ CGridCellBase* pCell = GetCell(nRow, nCol);
+ if (!pCell)
+ return FALSE;
+
+ pCell->SetText(str);
+
+ SetModified(TRUE, nRow, nCol);
+ return TRUE;
+}
+
+#if !defined(_WIN32_WCE) || (_WIN32_WCE >= 210)
+// EFW - 06/13/99 - Added to support printf-style formatting codes
+BOOL CGridCtrl::SetItemTextFmt(int nRow, int nCol, LPCTSTR szFmt, ...)
+{
+ if (GetVirtualMode())
+ return FALSE;
+
+ CString strText;
+
+ va_list argptr;
+
+ CGridCellBase* pCell = GetCell(nRow, nCol);
+ if (!pCell)
+ return FALSE;
+
+ // Format the message text
+ va_start(argptr, szFmt);
+ strText.FormatV(szFmt, argptr);
+ va_end(argptr);
+
+ pCell->SetText(strText);
+
+ SetModified(TRUE, nRow, nCol);
+ return TRUE;
+}
+
+// EFW - 06/13/99 - Added to support string resource ID. Supports
+// a variable argument list too.
+BOOL CGridCtrl::SetItemTextFmtID(int nRow, int nCol, UINT nID, ...)
+{
+ if (GetVirtualMode())
+ return FALSE;
+
+ CString strFmt, strText;
+ va_list argptr;
+
+ CGridCellBase* pCell = GetCell(nRow, nCol);
+ if (!pCell)
+ return FALSE;
+
+ // Format the message text
+ va_start(argptr, nID);
+ VERIFY(strFmt.LoadString(nID));
+ strText.FormatV(strFmt, argptr);
+ va_end(argptr);
+
+ pCell->SetText(strText);
+
+ SetModified(TRUE, nRow, nCol);
+ return TRUE;
+}
+#endif
+
+BOOL CGridCtrl::SetItemData(int nRow, int nCol, LPARAM lParam)
+{
+ if (GetVirtualMode())
+ return FALSE;
+
+ CGridCellBase* pCell = GetCell(nRow, nCol);
+ if (!pCell)
+ return FALSE;
+
+ pCell->SetData(lParam);
+ SetModified(TRUE, nRow, nCol);
+ return TRUE;
+}
+
+LPARAM CGridCtrl::GetItemData(int nRow, int nCol) const
+{
+ CGridCellBase* pCell = GetCell(nRow, nCol);
+ if (!pCell)
+ return (LPARAM) 0;
+
+ return pCell->GetData();
+}
+
+BOOL CGridCtrl::SetItemImage(int nRow, int nCol, int iImage)
+{
+ if (GetVirtualMode())
+ return FALSE;
+
+ CGridCellBase* pCell = GetCell(nRow, nCol);
+ if (!pCell)
+ return FALSE;
+
+ pCell->SetImage(iImage);
+ SetModified(TRUE, nRow, nCol);
+ return TRUE;
+}
+
+int CGridCtrl::GetItemImage(int nRow, int nCol) const
+{
+ CGridCellBase* pCell = GetCell(nRow, nCol);
+// ASSERT(pCell);
+ if (!pCell)
+ return -1;
+
+ return pCell->GetImage();
+}
+
+BOOL CGridCtrl::SetItemState(int nRow, int nCol, UINT state)
+{
+ BOOL bSelected = IsCellSelected(nRow, nCol);
+
+ // If the cell is being unselected, remove it from the selected list
+ if (bSelected && !(state & GVIS_SELECTED))
+ {
+ CCellID cell;
+ DWORD key = MAKELONG(nRow, nCol);
+
+ if (m_SelectedCellMap.Lookup(key, (CCellID&)cell))
+ m_SelectedCellMap.RemoveKey(key);
+ }
+
+ // If cell is being selected, add it to the list of selected cells
+ else if (!bSelected && (state & GVIS_SELECTED))
+ {
+ CCellID cell(nRow, nCol);
+ m_SelectedCellMap.SetAt(MAKELONG(nRow, nCol), cell);
+ }
+
+ if (GetVirtualMode())
+ return FALSE;
+
+ CGridCellBase* pCell = GetCell(nRow, nCol);
+// ASSERT(pCell);
+ if (!pCell)
+ return FALSE;
+
+ // Set the cell's state
+ pCell->SetState(state);
+
+ return TRUE;
+}
+
+UINT CGridCtrl::GetItemState(int nRow, int nCol) const
+{
+ CGridCellBase* pCell = GetCell(nRow, nCol);
+// ASSERT(pCell);
+ if (!pCell)
+ return 0;
+
+ return pCell->GetState();
+}
+
+BOOL CGridCtrl::SetItemFormat(int nRow, int nCol, UINT nFormat)
+{
+ if (GetVirtualMode())
+ return FALSE;
+
+ CGridCellBase* pCell = GetCell(nRow, nCol);
+// ASSERT(pCell);
+ if (!pCell)
+ return FALSE;
+
+ pCell->SetFormat(nFormat);
+ return TRUE;
+}
+
+UINT CGridCtrl::GetItemFormat(int nRow, int nCol) const
+{
+ CGridCellBase* pCell = GetCell(nRow, nCol);
+// ASSERT(pCell);
+ if (!pCell)
+ return 0;
+
+ return pCell->GetFormat();
+}
+
+BOOL CGridCtrl::SetItemBkColour(int nRow, int nCol, COLORREF cr /* = CLR_DEFAULT */)
+{
+ if (GetVirtualMode())
+ return FALSE;
+
+ CGridCellBase* pCell = GetCell(nRow, nCol);
+// ASSERT(pCell);
+ if (!pCell)
+ return FALSE;
+
+ pCell->SetBackClr(cr);
+ return TRUE;
+}
+
+COLORREF CGridCtrl::GetItemBkColour(int nRow, int nCol) const
+{
+ CGridCellBase* pCell = GetCell(nRow, nCol);
+// ASSERT(pCell);
+ if (!pCell)
+ return 0;
+
+ return pCell->GetBackClr();
+}
+
+BOOL CGridCtrl::SetItemFgColour(int nRow, int nCol, COLORREF cr /* = CLR_DEFAULT */)
+{
+ if (GetVirtualMode())
+ return FALSE;
+
+ CGridCellBase* pCell = GetCell(nRow, nCol);
+// ASSERT(pCell);
+ if (!pCell)
+ return FALSE;
+
+ pCell->SetTextClr(cr);
+ return TRUE;
+}
+
+COLORREF CGridCtrl::GetItemFgColour(int nRow, int nCol) const
+{
+ CGridCellBase* pCell = GetCell(nRow, nCol);
+// ASSERT(pCell);
+ if (!pCell)
+ return 0;
+
+ return pCell->GetTextClr();
+}
+
+BOOL CGridCtrl::SetItemFont(int nRow, int nCol, const LOGFONT* plf)
+{
+ if (GetVirtualMode())
+ return FALSE;
+
+ CGridCellBase* pCell = GetCell(nRow, nCol);
+// ASSERT(pCell);
+ if (!pCell)
+ return FALSE;
+
+ pCell->SetFont(plf);
+
+ return TRUE;
+}
+
+const LOGFONT* CGridCtrl::GetItemFont(int nRow, int nCol)
+{
+ CGridCellBase* pCell = GetCell(nRow, nCol);
+// ASSERT(pCell);
+ if (!pCell)
+ return GetDefaultCell(nRow < GetFixedRowCount(), nCol < GetFixedColumnCount())->GetFont();
+
+ return pCell->GetFont();
+}
+
+BOOL CGridCtrl::IsItemEditing(int nRow, int nCol)
+{
+ CGridCellBase* pCell = GetCell(nRow, nCol);
+// ASSERT(pCell);
+ if (!pCell)
+ return FALSE;
+
+ return pCell->IsEditing();
+}
+
+////////////////////////////////////////////////////////////////////////////////////
+// Row/Column size functions
+
+long CGridCtrl::GetVirtualWidth() const
+{
+ long lVirtualWidth = 0;
+ int iColCount = GetColumnCount();
+ for (int i = 0; i < iColCount; i++)
+ lVirtualWidth += m_arColWidths[i];
+
+ return lVirtualWidth;
+}
+
+long CGridCtrl::GetVirtualHeight() const
+{
+ long lVirtualHeight = 0;
+ int iRowCount = GetRowCount();
+ for (int i = 0; i < iRowCount; i++)
+ lVirtualHeight += m_arRowHeights[i];
+
+ return lVirtualHeight;
+}
+
+int CGridCtrl::GetRowHeight(int nRow) const
+{
+// ASSERT(nRow >= 0 && nRow < m_nRows);
+ if (nRow < 0 || nRow >= m_nRows)
+ return -1;
+
+ return m_arRowHeights[nRow];
+}
+
+int CGridCtrl::GetColumnWidth(int nCol) const
+{
+// ASSERT(nCol >= 0 && nCol < m_nCols);
+ if (nCol < 0 || nCol >= m_nCols)
+ return -1;
+
+ return m_arColWidths[m_arColOrder[nCol]];
+}
+
+BOOL CGridCtrl::SetRowHeight(int nRow, int height)
+{
+// ASSERT(nRow >= 0 && nRow < m_nRows && height >= 0);
+ if (nRow < 0 || nRow >= m_nRows || height < 0)
+ return FALSE;
+
+ m_arRowHeights[nRow] = height;
+ ResetScrollBars();
+
+ return TRUE;
+}
+
+BOOL CGridCtrl::SetColumnWidth(int nCol, int width)
+{
+// ASSERT(nCol >= 0 && nCol < m_nCols && width >= 0);
+ if (nCol < 0 || nCol >= m_nCols || width < 0)
+ return FALSE;
+
+ m_arColWidths[m_arColOrder[nCol]] = width;
+ ResetScrollBars();
+
+ return TRUE;
+}
+
+// LUC
+int CGridCtrl::GetFixedRowHeight(BOOL bIncludeFreezedRows /*=FALSE*/) const
+{
+ int nHeight = 0;
+ int i;
+ for (i = 0; i < m_nFixedRows; i++)
+ nHeight += GetRowHeight(i);
+
+ if(bIncludeFreezedRows)
+ {
+ for ( ; i < (m_nFixedRows + m_nFreezedRows); i++)
+ nHeight += GetRowHeight(i);
+ }
+
+ return nHeight;
+}
+
+// LUC
+int CGridCtrl::GetFixedColumnWidth(BOOL bIncludeFreezedCols /*=FALSE*/) const
+{
+ int nWidth = 0;
+ int i;
+ for (i = 0; i < m_nFixedCols; i++)
+ nWidth += GetColumnWidth(i);
+
+ if(bIncludeFreezedCols)
+ {
+ for ( ; i < (m_nFixedCols + m_nFreezedCols); i++)
+ nWidth += GetColumnWidth(i);
+ }
+
+ return nWidth;
+}
+
+BOOL CGridCtrl::AutoSizeColumn(int nCol, UINT nAutoSizeStyle /*=GVS_DEFAULT*/,
+ BOOL bResetScroll /*=TRUE*/)
+{
+// ASSERT(nCol >= 0 && nCol < m_nCols);
+ if (nCol < 0 || nCol >= m_nCols)
+ return FALSE;
+
+ // Skip hidden columns when autosizing
+ if( GetColumnWidth( nCol) <=0 )
+ return FALSE;
+
+ CSize size;
+ CDC* pDC = GetDC();
+ if (!pDC)
+ return FALSE;
+
+ int nWidth = 0;
+
+// ASSERT(GVS_DEFAULT <= nAutoSizeStyle && nAutoSizeStyle <= GVS_BOTH);
+ if (nAutoSizeStyle == GVS_DEFAULT)
+ nAutoSizeStyle = GetAutoSizeStyle();
+
+ int nStartRow = (nAutoSizeStyle & GVS_HEADER)? 0 : GetFixedRowCount();
+ int nEndRow = (nAutoSizeStyle & GVS_DATA)? GetRowCount()-1 : GetFixedRowCount()-1;
+
+ if (GetVirtualMode())
+ SendCacheHintToParent(CCellRange(nStartRow, nCol, nEndRow, nCol));
+
+ for (int nRow = nStartRow; nRow <= nEndRow; nRow++)
+ {
+ CGridCellBase* pCell = GetCell(nRow, nCol);
+ if (pCell)
+ size = pCell->GetCellExtent(pDC);
+ if (size.cx > nWidth)
+ nWidth = size.cx;
+ }
+
+ if (GetVirtualMode())
+ SendCacheHintToParent(CCellRange(-1,-1,-1,-1));
+
+ m_arColWidths[nCol] = nWidth;
+
+ ReleaseDC(pDC);
+ if (bResetScroll)
+ ResetScrollBars();
+
+ return TRUE;
+}
+
+BOOL CGridCtrl::AutoSizeRow(int nRow, BOOL bResetScroll /*=TRUE*/)
+{
+// ASSERT(nRow >= 0 && nRow < m_nRows);
+ if (nRow < 0 || nRow >= m_nRows)
+ return FALSE;
+
+ // Skip hidden rows when autosizing
+ if( GetRowHeight( nRow) <=0 )
+ return FALSE;
+
+ CSize size;
+ CDC* pDC = GetDC();
+ if (!pDC)
+ return FALSE;
+
+ int nHeight = 0;
+ int nNumColumns = GetColumnCount();
+
+ if (GetVirtualMode())
+ SendCacheHintToParent(CCellRange(nRow, 0, nRow, nNumColumns));
+
+ for (int nCol = 0; nCol < nNumColumns; nCol++)
+ {
+ CGridCellBase* pCell = GetCell(nRow, nCol);
+ if (pCell)
+ size = pCell->GetCellExtent(pDC);
+ if (size.cy > nHeight)
+ nHeight = size.cy;
+ }
+ m_arRowHeights[nRow] = nHeight;
+
+ if (GetVirtualMode())
+ SendCacheHintToParent(CCellRange(-1,-1,-1,-1));
+
+ ReleaseDC(pDC);
+ if (bResetScroll)
+ ResetScrollBars();
+
+ return TRUE;
+}
+
+void CGridCtrl::AutoSizeColumns(UINT nAutoSizeStyle /*=GVS_DEFAULT*/)
+{
+ int nNumColumns = GetColumnCount();
+ for (int nCol = 0; nCol < nNumColumns; nCol++)
+ {
+ // Skip hidden columns when autosizing
+ if( GetColumnWidth( nCol) > 0 )
+ AutoSizeColumn(nCol, nAutoSizeStyle, FALSE);
+ }
+ ResetScrollBars();
+}
+
+void CGridCtrl::AutoSizeRows()
+{
+ int nNumRows = GetRowCount();
+ for (int nRow = 0; nRow < nNumRows; nRow++)
+ {
+ // Skip hidden rows when autosizing
+ if( GetRowHeight( nRow) > 0 )
+ AutoSizeRow(nRow, FALSE);
+ }
+ ResetScrollBars();
+}
+
+// sizes all rows and columns
+// faster than calling both AutoSizeColumns() and AutoSizeRows()
+void CGridCtrl::AutoSize(UINT nAutoSizeStyle /*=GVS_DEFAULT*/)
+{
+ CDC* pDC = GetDC();
+ if (!pDC)
+ return;
+
+ int nNumColumns = GetColumnCount();
+
+ int nCol, nRow;
+
+// ASSERT(GVS_DEFAULT <= nAutoSizeStyle && nAutoSizeStyle <= GVS_BOTH);
+ if (nAutoSizeStyle == GVS_DEFAULT)
+ nAutoSizeStyle = GetAutoSizeStyle();
+
+ int nStartRow = (nAutoSizeStyle & GVS_HEADER)? 0 : GetFixedRowCount();
+ int nEndRow = (nAutoSizeStyle & GVS_DATA)? GetRowCount()-1 : GetFixedRowCount()-1;
+
+ if (GetVirtualMode())
+ SendCacheHintToParent(CCellRange(nStartRow, 0, nEndRow, nNumColumns));
+
+ // Row initialisation - only work on rows whose height is > 0
+ for (nRow = nStartRow; nRow <= nEndRow; nRow++)
+ {
+ if( GetRowHeight( nRow) > 0 )
+ m_arRowHeights[nRow] = 1;
+ }
+
+ CSize size;
+ for (nCol = 0; nCol < nNumColumns; nCol++)
+ {
+ // Don't size hidden columns or rows
+ if( GetColumnWidth( nCol) > 0 )
+ {
+ // Skip columns that are hidden, but now initialize
+ m_arColWidths[nCol] = 0;
+ for (nRow = nStartRow; nRow <= nEndRow; nRow++)
+ {
+ if( GetRowHeight( nRow) > 0 )
+ {
+ CGridCellBase* pCell = GetCell(nRow, nCol);
+ if (pCell)
+ size = pCell->GetCellExtent(pDC);
+ if (size.cx >(int) m_arColWidths[nCol])
+ m_arColWidths[nCol] = size.cx;
+ if (size.cy >(int) m_arRowHeights[nRow])
+ m_arRowHeights[nRow] = size.cy;
+ }
+ }
+ }
+ }
+
+ if (GetVirtualMode())
+ SendCacheHintToParent(CCellRange(-1,-1,-1,-1));
+
+ ReleaseDC(pDC);
+
+ ResetScrollBars();
+ Refresh();
+}
+
+// Expands the columns to fit the screen space. If bExpandFixed is FALSE then fixed
+// columns will not be affected
+void CGridCtrl::ExpandColumnsToFit(BOOL bExpandFixed /*=TRUE*/)
+{
+ if (bExpandFixed)
+ {
+ if (GetColumnCount() <= 0) return;
+ }
+ else
+ {
+ if (GetColumnCount() <= GetFixedColumnCount()) return;
+ }
+
+ EnableScrollBars(SB_HORZ, FALSE);
+
+ int col;
+ CRect rect;
+ GetClientRect(rect);
+
+ int nFirstColumn = (bExpandFixed)? 0 : GetFixedColumnCount();
+
+ int nNumColumnsAffected = 0;
+ for (col = nFirstColumn; col < GetColumnCount(); col++)
+ {
+ if (m_arColWidths[col] > 0)
+ nNumColumnsAffected++;
+ }
+
+ if (nNumColumnsAffected <= 0)
+ return;
+
+ long virtualWidth = GetVirtualWidth();
+ int nDifference = rect.Width() -(int) virtualWidth;
+ int nColumnAdjustment = nDifference / nNumColumnsAffected;
+
+ for (col = nFirstColumn; col < GetColumnCount(); col++)
+ {
+ if (m_arColWidths[col] > 0)
+ m_arColWidths[col] += nColumnAdjustment;
+ }
+
+ if (nDifference > 0)
+ {
+ int leftOver = nDifference % nNumColumnsAffected;
+ for (int nCount = 0, col = nFirstColumn;
+ (col < GetColumnCount()) && (nCount < leftOver); col++, nCount++)
+ {
+ if (m_arColWidths[col] > 0)
+ m_arColWidths[col] += 1;
+ }
+ }
+ else
+ {
+ int leftOver = (-nDifference) % nNumColumnsAffected;
+ for (int nCount = 0, col = nFirstColumn;
+ (col < GetColumnCount()) && (nCount < leftOver); col++, nCount++)
+ {
+ if (m_arColWidths[col] > 0)
+ m_arColWidths[col] -= 1;
+ }
+ }
+
+ Refresh();
+
+ ResetScrollBars();
+}
+
+void CGridCtrl::ExpandLastColumn()
+{
+ if (GetColumnCount() <= 0)
+ return;
+
+ // Search for last non-hidden column
+ int nLastColumn = GetColumnCount()-1;
+ while (m_arColWidths[nLastColumn] <= 0)
+ nLastColumn--;
+
+ if (nLastColumn <= 0)
+ return;
+
+ EnableScrollBars(SB_HORZ, FALSE);
+
+ CRect rect;
+ GetClientRect(rect);
+
+ long virtualWidth = GetVirtualWidth();
+ int nDifference = rect.Width() -(int) virtualWidth;
+
+ if (nDifference > 0)
+ {
+ //if (GetVirtualHeight() > rect.Height())
+ // nDifference -= GetSystemMetrics(SM_CXVSCROLL);
+
+ m_arColWidths[ nLastColumn ] += nDifference;
+ Refresh();
+ }
+
+ ResetScrollBars();
+}
+
+// Expands the rows to fit the screen space. If bExpandFixed is FALSE then fixed
+// rows will not be affected
+void CGridCtrl::ExpandRowsToFit(BOOL bExpandFixed /*=TRUE*/)
+{
+ if (bExpandFixed)
+ {
+ if (GetRowCount() <= 0) return;
+ }
+ else
+ {
+ if (GetRowCount() <= GetFixedRowCount()) return;
+ }
+
+ EnableScrollBars(SB_VERT, FALSE);
+
+ int row;
+ CRect rect;
+ GetClientRect(rect);
+
+ int nFirstRow = (bExpandFixed)? 0 : GetFixedRowCount();
+
+ int nNumRowsAffected = 0;
+ for (row = nFirstRow; row < GetRowCount(); row++)
+ {
+ if (m_arRowHeights[row] > 0)
+ nNumRowsAffected++;
+ }
+
+ if (nNumRowsAffected <= 0)
+ return;
+
+ long virtualHeight = GetVirtualHeight();
+ int nDifference = rect.Height() -(int) virtualHeight;
+ int nRowAdjustment = nDifference / nNumRowsAffected;
+
+ for (row = nFirstRow; row < GetRowCount(); row++)
+ {
+ if (m_arRowHeights[row] > 0)
+ m_arRowHeights[row] += nRowAdjustment;
+ }
+
+ if (nDifference > 0)
+ {
+ int leftOver = nDifference % nNumRowsAffected;
+ for (int nCount = 0, row = nFirstRow;
+ (row < GetRowCount()) && (nCount < leftOver); row++, nCount++)
+ {
+ if (m_arRowHeights[row] > 0)
+ m_arRowHeights[row] += 1;
+ }
+ }
+ else
+ {
+ int leftOver = (-nDifference) % nNumRowsAffected;
+ for (int nCount = 0, row = nFirstRow;
+ (row < GetRowCount()) && (nCount < leftOver); row++, nCount++)
+ {
+ if (m_arRowHeights[row] > 0)
+ m_arRowHeights[row] -= 1;
+ }
+ }
+
+ Refresh();
+
+ ResetScrollBars();
+}
+
+// Expands the cells to fit the screen space. If bExpandFixed is FALSE then fixed
+// cells will not be affected
+void CGridCtrl::ExpandToFit(BOOL bExpandFixed /*=TRUE*/)
+{
+ ExpandColumnsToFit(bExpandFixed); // This will remove any existing horz scrollbar
+ ExpandRowsToFit(bExpandFixed); // This will remove any existing vert scrollbar
+ ExpandColumnsToFit(bExpandFixed); // Just in case the first adjustment was with a vert
+ // scrollbar in place
+ Refresh();
+}
+
+/////////////////////////////////////////////////////////////////////////////////////
+// Attributes
+
+void CGridCtrl::SetVirtualMode(BOOL bVirtual)
+{
+ DeleteAllItems();
+ m_bVirtualMode = bVirtual;
+
+ // Force some defaults here.
+ if (m_bVirtualMode)
+ {
+ SetEditable(FALSE);
+ SetAutoSizeStyle(GVS_HEADER);
+ SetFixedColumnSelection(FALSE);
+ SetFixedRowSelection(FALSE);
+ ResetVirtualOrder();
+ }
+}
+
+void CGridCtrl::SetGridLines(int nWhichLines /*=GVL_BOTH*/)
+{
+ m_nGridLines = nWhichLines;
+ Refresh();
+}
+
+void CGridCtrl::SetListMode(BOOL bEnableListMode /*=TRUE*/)
+{
+ ResetSelectedRange();
+ SetSortColumn(-1);
+ m_bListMode = bEnableListMode;
+ SetFixedRowSelection(FALSE);
+ Refresh();
+}
+
+void CGridCtrl::SetSortColumn(int nCol)
+{
+ if (m_nSortColumn >= 0)
+ InvalidateCellRect(0, m_nSortColumn);
+ m_nSortColumn = nCol;
+ if (nCol >= 0)
+ InvalidateCellRect(0, nCol);
+}
+
+BOOL CGridCtrl::IsCellFixed(int nRow, int nCol)
+{
+ return (nRow < GetFixedRowCount() || nCol < GetFixedColumnCount());
+}
+
+void CGridCtrl::SetModified(BOOL bModified /*=TRUE*/, int nRow /*=-1*/, int nCol /*=-1*/)
+{
+ // Cannot guarantee sorting anymore...
+ if (nCol < 0 || nCol == GetSortColumn())
+ SetSortColumn(-1);
+
+ if (nRow >= 0 && nCol >= 0)
+ {
+ if (bModified)
+ {
+ SetItemState(nRow, nCol, GetItemState(nRow, nCol) | GVIS_MODIFIED);
+ m_bModified = TRUE;
+ }
+ else
+ SetItemState(nRow, nCol, GetItemState(nRow, nCol) & ~GVIS_MODIFIED);
+ }
+ else
+ m_bModified = bModified;
+
+ if (!m_bModified)
+ {
+ for (int row = 0; row < GetRowCount(); row++)
+ for (int col = 0; col < GetColumnCount(); col++)
+ SetItemState(row, col, GetItemState(row, col) & ~GVIS_MODIFIED);
+ }
+}
+
+BOOL CGridCtrl::GetModified(int nRow /*=-1*/, int nCol /*=-1*/)
+{
+ if (nRow >= 0 && nCol >= 0)
+ return ( (GetItemState(nRow, nCol) & GVIS_MODIFIED) == GVIS_MODIFIED );
+ else
+ return m_bModified;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////
+// GridCtrl cell visibility tests and invalidation/redraw functions
+
+void CGridCtrl::Refresh()
+{
+ if (GetSafeHwnd() && m_bAllowDraw)
+ Invalidate();
+}
+
+// EnsureVisible supplied by Roelf Werkman
+void CGridCtrl::EnsureVisible(int nRow, int nCol)
+{
+ if (!m_bAllowDraw)
+ return;
+
+ CRect rectWindow;
+ /*
+ // set the scroll to the approximate position of row (Nigel Page-Jones)
+ int nPos = (int)((float)nRow / GetRowCount() * 1000);
+ float fPos = (float)nPos / 1000;
+ SCROLLINFO scrollInfo;
+ GetScrollInfo(SB_VERT, &scrollInfo);
+ scrollInfo.nPos = (int)(scrollInfo.nMax * fPos);
+ SetScrollInfo(SB_VERT, &scrollInfo, FALSE);
+
+ GetClientRect(rectWindow);
+
+ // redraw cells if necessary (Nigel Page-Jones)
+ CCellID idTopLeft = GetTopleftNonFixedCell(FALSE);
+ CCellID idNewTopLeft = GetTopleftNonFixedCell(TRUE);
+ if (idNewTopLeft != idTopLeft)
+ {
+ rectWindow.top = GetFixedRowHeight();
+ InvalidateRect(rectWindow);
+ }
+ */
+
+ // We are going to send some scroll messages, which will steal the focus
+ // from it's rightful owner. Squirrel it away ourselves so we can give
+ // it back. (Damir)
+ CWnd* pFocusWnd = GetFocus();
+
+ CCellRange VisibleCells = GetVisibleNonFixedCellRange();
+
+ int right = nCol - VisibleCells.GetMaxCol();
+ int left = VisibleCells.GetMinCol() - nCol;
+ int down = nRow - VisibleCells.GetMaxRow();
+ int up = VisibleCells.GetMinRow() - nRow;
+
+ int iColumnStart;
+ int iRowStart;
+
+ iColumnStart = VisibleCells.GetMaxCol() + 1;
+ while( right > 0 )
+ {
+ if( GetColumnWidth( iColumnStart ) > 0 )
+ SendMessage( WM_HSCROLL, SB_LINERIGHT, 0 );
+
+ right--;
+ iColumnStart++;
+ }
+
+ iColumnStart = VisibleCells.GetMinCol() - 1;
+ while( left > 0 )
+ {
+ if( GetColumnWidth( iColumnStart ) > 0 )
+ SendMessage( WM_HSCROLL, SB_LINELEFT, 0 );
+ left--;
+ iColumnStart--;
+ }
+
+ iRowStart = VisibleCells.GetMaxRow() + 1;
+ while( down > 0 )
+ {
+ if( GetRowHeight( iRowStart ) > 0 )
+ SendMessage( WM_VSCROLL, SB_LINEDOWN, 0 );
+ down--;
+ iRowStart++;
+ }
+
+ iRowStart = VisibleCells.GetMinRow() - 1;
+ while( up > 0 )
+ {
+ if( GetRowHeight( iRowStart ) > 0 )
+ SendMessage( WM_VSCROLL, SB_LINEUP, 0 );
+ up--;
+ iRowStart--;
+ }
+
+ // Move one more if we only see a snall bit of the cell
+ CRect rectCell;
+ if (!GetCellRect(nRow, nCol, rectCell))
+ {
+ if (pFocusWnd && ::IsWindow(pFocusWnd->GetSafeHwnd()))
+ pFocusWnd->SetFocus();
+ return;
+ }
+
+ GetClientRect(rectWindow);
+
+ // LUC
+ // The previous fix was fixed properly by Martin Richter
+ while (rectCell.right > rectWindow.right
+ && rectCell.left > GetFixedColumnWidth(m_bExcludeFreezedColsFromSelection)
+ && IsVisibleHScroll() // Junlin Xu: added to prevent infinite loop
+ )
+ {
+ SendMessage(WM_HSCROLL, SB_LINERIGHT, 0);
+ if (!GetCellRect(nRow, nCol, rectCell))
+ {
+ pFocusWnd->SetFocus();
+ return;
+ }
+ }
+
+ // LUC
+ while (rectCell.bottom > rectWindow.bottom
+ && rectCell.top > GetFixedRowHeight(m_bExcludeFreezedRowsFromSelection)
+ && IsVisibleVScroll() // Junlin Xu: added to prevent infinite loop
+ )
+ {
+ SendMessage(WM_VSCROLL, SB_LINEDOWN, 0);
+ if (!GetCellRect(nRow, nCol, rectCell))
+ {
+ pFocusWnd->SetFocus();
+ return;
+ }
+ }
+
+ // restore focus to whoever owned it
+ pFocusWnd->SetFocus();
+}
+
+BOOL CGridCtrl::IsCellEditable(CCellID &cell) const
+{
+ return IsCellEditable(cell.row, cell.col);
+}
+
+BOOL CGridCtrl::IsCellEditable(int nRow, int nCol) const
+{
+ return IsEditable() && ((GetItemState(nRow, nCol) & GVIS_READONLY) != GVIS_READONLY);
+}
+
+BOOL CGridCtrl::IsCellSelected(CCellID &cell) const
+{
+ return IsCellSelected(cell.row, cell.col);
+}
+
+BOOL CGridCtrl::IsCellSelected(int nRow, int nCol) const
+{
+ if (GetVirtualMode())
+ {
+ if (!IsSelectable())
+ return FALSE;
+
+ CCellID cell;
+ DWORD key = MAKELONG(nRow, nCol);
+
+ return (m_SelectedCellMap.Lookup(key, (CCellID&)cell));
+ }
+ else
+ return IsSelectable() && ((GetItemState(nRow, nCol) & GVIS_SELECTED) == GVIS_SELECTED);
+}
+
+BOOL CGridCtrl::IsCellVisible(CCellID cell)
+{
+ return IsCellVisible(cell.row, cell.col);
+}
+
+BOOL CGridCtrl::IsCellVisible(int nRow, int nCol)
+{
+ if (!IsWindow(m_hWnd))
+ return FALSE;
+
+ int x, y;
+
+ // LUC
+ CCellID TopLeft;
+ if (nCol >= GetFixedColumnCount(TRUE) || nRow >= GetFixedRowCount(TRUE))
+ {
+ TopLeft = GetTopleftNonFixedCell();
+ if (nCol >= GetFixedColumnCount(TRUE) && nCol < TopLeft.col)
+ return FALSE;
+ if (nRow >= GetFixedRowCount(TRUE) && nRow < TopLeft.row)
+ return FALSE;
+ }
+
+ CRect rect;
+ GetClientRect(rect);
+ if (nCol < GetFixedColumnCount(TRUE))
+ {
+ x = 0;
+ for (int i = 0; i <= nCol; i++)
+ {
+ if (x >= rect.right)
+ return FALSE;
+ x += GetColumnWidth(i);
+ }
+ }
+ else
+ {
+ x = GetFixedColumnWidth(TRUE);
+ for (int i = TopLeft.col; i <= nCol; i++)
+ {
+ if (x >= rect.right)
+ return FALSE;
+ x += GetColumnWidth(i);
+ }
+ }
+
+ if (nRow < GetFixedRowCount(TRUE))
+ {
+ y = 0;
+ for (int i = 0; i <= nRow; i++)
+ {
+ if (y >= rect.bottom)
+ return FALSE;
+ y += GetRowHeight(i);
+ }
+ }
+ else
+ {
+ if (nRow < TopLeft.row)
+ return FALSE;
+ y = GetFixedRowHeight(TRUE);
+ for (int i = TopLeft.row; i <= nRow; i++)
+ {
+ if (y >= rect.bottom)
+ return FALSE;
+ y += GetRowHeight(i);
+ }
+ }
+
+ return TRUE;
+}
+
+BOOL CGridCtrl::InvalidateCellRect(const CCellID& cell)
+{
+ return InvalidateCellRect(cell.row, cell.col);
+}
+
+BOOL CGridCtrl::InvalidateCellRect(const int row, const int col)
+{
+ if (!::IsWindow(GetSafeHwnd()) || !m_bAllowDraw)
+ return FALSE;
+
+ if (!IsValid(row, col))
+ return FALSE;
+
+ if (!IsCellVisible(row, col))
+ return FALSE;
+
+ CRect rect;
+ if (!GetCellRect(row, col, rect))
+ return FALSE;
+
+ // LUC
+ int nRow = row;
+ int nCol = col;
+ GetTopLeftMergedCell(nRow, nCol, rect);
+
+ rect.right++;
+ rect.bottom++;
+ InvalidateRect(rect, TRUE);
+
+ return TRUE;
+}
+
+BOOL CGridCtrl::InvalidateCellRect(const CCellRange& cellRange)
+{
+// ASSERT(IsValid(cellRange));
+ if (!::IsWindow(GetSafeHwnd()) || !m_bAllowDraw)
+ return FALSE;
+
+ CCellRange visibleCellRange = GetVisibleNonFixedCellRange().Intersect(cellRange);
+
+ CRect rect;
+ if (!GetCellRangeRect(visibleCellRange, rect))
+ return FALSE;
+
+ rect.right++;
+ rect.bottom++;
+ InvalidateRect(rect, TRUE);
+
+ return TRUE;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// CGridCtrl Mouse stuff
+
+// Handles mouse wheel notifications
+// Note - if this doesn't work for win95 then use OnRegisteredMouseWheel instead
+#if !defined(_WIN32_WCE) && (_MFC_VER >= 0x0421)
+BOOL CGridCtrl::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt)
+{
+ // A m_nRowsPerWheelNotch value less than 0 indicates that the mouse
+ // wheel scrolls whole pages, not just lines.
+ if (m_nRowsPerWheelNotch == -1)
+ {
+ int nPagesScrolled = zDelta / 120;
+
+ if (nPagesScrolled > 0)
+ {
+ for (int i = 0; i < nPagesScrolled; i++)
+ {
+ PostMessage(WM_VSCROLL, SB_PAGEUP, 0);
+ }
+ }
+ else
+ {
+ for (int i = 0; i > nPagesScrolled; i--)
+ {
+ PostMessage(WM_VSCROLL, SB_PAGEDOWN, 0);
+ }
+ }
+ }
+ else
+ {
+ int nRowsScrolled = m_nRowsPerWheelNotch * zDelta / 120;
+
+ if (nRowsScrolled > 0)
+ {
+ for (int i = 0; i < nRowsScrolled; i++)
+ {
+ PostMessage(WM_VSCROLL, SB_LINEUP, 0);
+ }
+ }
+ else
+ {
+ for (int i = 0; i > nRowsScrolled; i--)
+ {
+ PostMessage(WM_VSCROLL, SB_LINEDOWN, 0);
+ }
+ }
+ }
+
+ return CWnd::OnMouseWheel(nFlags, zDelta, pt);
+}
+#endif // !defined(_WIN32_WCE) && (_MFC_VER >= 0x0421)
+
+void CGridCtrl::OnMouseMove(UINT /*nFlags*/, CPoint point)
+{
+ CRect rect;
+ GetClientRect(rect);
+
+#ifndef GRIDCONTROL_NO_DRAGDROP
+ // If outside client area, return (unless we are drag n dropping)
+ if (m_MouseMode != MOUSE_DRAGGING && !rect.PtInRect(point))
+ return;
+#endif
+
+ // Sometimes a MOUSEMOVE message can come after the left buttons
+ // has been let go, but before the BUTTONUP message hs been processed.
+ // We'll keep track of mouse buttons manually to avoid this.
+ // All bMouseButtonDown's have been replaced with the member m_bLMouseButtonDown
+ // BOOL bMouseButtonDown = ((nFlags & MK_LBUTTON) == MK_LBUTTON);
+
+ // If the left mouse button is up, then test to see if row/column sizing is imminent
+ if (!m_bLMouseButtonDown ||
+ (m_bLMouseButtonDown && m_MouseMode == MOUSE_NOTHING))
+ {
+ if (m_bAllowColumnResize && MouseOverColumnResizeArea(point))
+ {
+ if (m_MouseMode != MOUSE_OVER_COL_DIVIDE)
+ {
+#ifndef _WIN32_WCE_NO_CURSOR
+ SetCursor(AfxGetApp()->LoadStandardCursor(IDC_SIZEWE));
+#endif
+ m_MouseMode = MOUSE_OVER_COL_DIVIDE;
+ }
+ }
+ else if (m_bAllowRowResize && MouseOverRowResizeArea(point))
+ {
+ if (m_MouseMode != MOUSE_OVER_ROW_DIVIDE)
+ {
+#ifndef _WIN32_WCE_NO_CURSOR
+ SetCursor(AfxGetApp()->LoadStandardCursor(IDC_SIZENS));
+#endif
+ m_MouseMode = MOUSE_OVER_ROW_DIVIDE;
+ }
+ }
+ else if (m_MouseMode != MOUSE_NOTHING)
+ {
+#ifndef _WIN32_WCE_NO_CURSOR
+ SetCursor(AfxGetApp()->LoadStandardCursor(IDC_ARROW));
+#endif
+ m_MouseMode = MOUSE_NOTHING;
+ }
+
+ if (m_MouseMode == MOUSE_NOTHING)
+ {
+ CGridCellBase* pCell = NULL;
+ CCellID idCurrentCell;
+ if (!GetVirtualMode() || m_bTitleTips)
+ {
+ // Let the cell know that a big fat cursor is currently hovering
+ // over it.
+ idCurrentCell = GetCellFromPt(point);
+ pCell = GetCell(idCurrentCell.row, idCurrentCell.col);
+ if (pCell)
+ pCell->OnMouseOver();
+ }
+
+#ifndef GRIDCONTROL_NO_TITLETIPS
+ // Titletips anyone? anyone?
+ if (m_bTitleTips)
+ {
+ CRect TextRect, CellRect;
+ if (pCell)
+ {
+ LPCTSTR szTipText = pCell->GetTipText();
+ if (!m_bRMouseButtonDown
+ && szTipText && szTipText[0]
+ && !pCell->IsEditing()
+ && GetCellRect( idCurrentCell.row, idCurrentCell.col, &TextRect)
+ && pCell->GetTipTextRect( &TextRect)
+ && GetCellRect(idCurrentCell.row, idCurrentCell.col, CellRect) )
+ {
+ // LUC
+ int row = idCurrentCell.row;
+ int col = idCurrentCell.col;
+ GetTopLeftMergedCell(row, col, CellRect);
+// TRACE0("Showing TitleTip\n");
+ m_TitleTip.Show(TextRect, pCell->GetTipText(), 0, CellRect,
+ pCell->GetFont(), GetTitleTipTextClr(), GetTitleTipBackClr());
+ }
+ }
+ }
+#endif
+ }
+
+ m_LastMousePoint = point;
+ return;
+ }
+
+ if (!IsValid(m_LeftClickDownCell))
+ {
+ m_LastMousePoint = point;
+ return;
+ }
+
+ // If the left mouse button is down, then process appropriately
+ if (m_bLMouseButtonDown)
+ {
+ switch (m_MouseMode)
+ {
+ case MOUSE_SELECT_ALL:
+ break;
+
+ case MOUSE_SELECT_COL:
+ case MOUSE_SELECT_ROW:
+ case MOUSE_SELECT_CELLS:
+ {
+ CCellID idCurrentCell = GetCellFromPt(point);
+ if (!IsValid(idCurrentCell))
+ return;
+
+ if (idCurrentCell != GetFocusCell())
+ {
+ OnSelecting(idCurrentCell);
+
+ // EFW - BUG FIX - Keep the appropriate cell row and/or
+ // column focused. A fix in SetFocusCell() will place
+ // the cursor in a non-fixed cell as needed.
+ // LUC
+ if((idCurrentCell.row >= GetFixedRowCount(m_bExcludeFreezedRowsFromSelection) &&
+ idCurrentCell.col >= GetFixedColumnCount(m_bExcludeFreezedColsFromSelection)) ||
+ m_MouseMode==MOUSE_SELECT_COL ||
+ m_MouseMode==MOUSE_SELECT_ROW)
+ {
+ SetFocusCell(idCurrentCell);
+ }
+ }
+ break;
+ }
+
+ case MOUSE_SIZING_COL:
+ {
+ CDC* pDC = GetDC();
+ if (!pDC)
+ break;
+
+ CRect oldInvertedRect(m_LastMousePoint.x, rect.top,
+ m_LastMousePoint.x + 2, rect.bottom);
+ pDC->InvertRect(&oldInvertedRect);
+ CRect newInvertedRect(point.x, rect.top,
+ point.x + 2, rect.bottom);
+ pDC->InvertRect(&newInvertedRect);
+ ReleaseDC(pDC);
+ }
+ break;
+
+ case MOUSE_SIZING_ROW:
+ {
+ CDC* pDC = GetDC();
+ if (!pDC)
+ break;
+
+ CRect oldInvertedRect(rect.left, m_LastMousePoint.y,
+ rect.right, m_LastMousePoint.y + 2);
+ pDC->InvertRect(&oldInvertedRect);
+ CRect newInvertedRect(rect.left, point.y,
+ rect.right, point.y + 2);
+ pDC->InvertRect(&newInvertedRect);
+ ReleaseDC(pDC);
+ }
+ break;
+
+#ifndef GRIDCONTROL_NO_DRAGDROP
+ case MOUSE_PREPARE_EDIT:
+ case MOUSE_PREPARE_DRAG:
+ m_MouseMode = MOUSE_PREPARE_DRAG;
+ OnBeginDrag();
+ break;
+#endif
+ }
+ }
+
+ m_LastMousePoint = point;
+}
+
+// Returns the point inside the cell that was clicked (coords relative to cell top left)
+CPoint CGridCtrl::GetPointClicked(int nRow, int nCol, const CPoint& point)
+{
+ CPoint PointCellOrigin;
+ if( !GetCellOrigin( nRow, nCol, &PointCellOrigin) )
+ return CPoint( 0, 0);
+
+ CPoint PointClickedCellRelative( point);
+ PointClickedCellRelative -= PointCellOrigin;
+ return PointClickedCellRelative;
+}
+
+void CGridCtrl::OnLButtonDblClk(UINT nFlags, CPoint point)
+{
+ TRACE0("CGridCtrl::OnLButtonDblClk\n");
+
+ // LUC
+ CCellID cellOriginal;
+ CCellID cell = GetCellFromPt(point, TRUE, cellOriginal);
+ if( !IsValid( cell) )
+ {
+ //ASSERT(FALSE);
+ return;
+ }
+
+#ifdef _WIN32_WCE
+ if (MouseOverColumnResizeArea(point))
+#else
+ if (m_MouseMode == MOUSE_OVER_COL_DIVIDE)
+#endif
+ {
+ CPoint start;
+ if (!GetCellOrigin(0, cell.col, &start))
+ return;
+
+ if (point.x - start.x < m_nResizeCaptureRange) // Clicked right of border
+ cell.col--;
+
+ // ignore columns that are hidden and look left towards first visible column
+ BOOL bFoundVisible = FALSE;
+ while( cell.col >= 0)
+ {
+ if( GetColumnWidth( cell.col) > 0)
+ {
+ bFoundVisible = TRUE;
+ break;
+ }
+ cell.col--;
+ }
+ if( !bFoundVisible)
+ return;
+
+ AutoSizeColumn(cell.col, GetAutoSizeStyle());
+ Invalidate();
+ }
+#ifdef _WIN32_WCE
+ else if (MouseOverRowResizeArea(point))
+#else
+ else if (m_MouseMode == MOUSE_OVER_ROW_DIVIDE)
+#endif
+ {
+ CPoint start;
+ if (!GetCellOrigin(0, cell.col, &start))
+ return;
+
+ if (point.y - start.y < m_nResizeCaptureRange) // Clicked below border
+ cell.row--;
+
+ // ignore rows that are hidden and look up towards first visible row
+ BOOL bFoundVisible = FALSE;
+ while( cell.row >= 0)
+ {
+ if( GetRowHeight( cell.row) > 0)
+ {
+ bFoundVisible = TRUE;
+ break;
+ }
+ cell.row--;
+ }
+ if( !bFoundVisible)
+ return;
+
+ AutoSizeRow(cell.row);
+ Invalidate();
+ }
+ else if (m_MouseMode == MOUSE_NOTHING)
+ {
+ CPoint pointClickedRel;
+ pointClickedRel = GetPointClicked( cell.row, cell.col, point);
+
+ CGridCellBase* pCell = NULL;
+ if (IsValid(cell))
+ pCell = GetCell(cell.row, cell.col);
+
+ // Clicked in the text area? Only then will cell selection work
+ BOOL bInTextArea = FALSE;
+ if (pCell)
+ {
+ // LUC
+ CRect rectCell;
+ if (GetCellRect(cellOriginal.row, cellOriginal.col, rectCell) && pCell->GetTextRect(rectCell))
+ bInTextArea = rectCell.PtInRect(point);
+ }
+
+ if (cell.row >= m_nFixedRows && IsValid(m_LeftClickDownCell) &&
+ cell.col >= m_nFixedCols && bInTextArea)
+ {
+ OnEditCell(cell.row, cell.col, pointClickedRel, VK_LBUTTON);
+ }
+ else if (m_bListMode)
+ {
+ if (!IsValid(cell))
+ return;
+ if (cell.row >= m_nFixedRows && cell.col >= m_nFixedCols && bInTextArea)
+ OnEditCell(cell.row, cell.col, pointClickedRel, VK_LBUTTON);
+ }
+
+ if (IsValid(cell))
+ {
+ CGridCellBase* pCell = GetCell(cell.row, cell.col);
+ if (pCell)
+ pCell->OnDblClick(pointClickedRel);
+ SendMessageToParent(cell.row, cell.col, NM_DBLCLK);
+ }
+ }
+
+ CWnd::OnLButtonDblClk(nFlags, point);
+}
+
+void CGridCtrl::OnLButtonDown(UINT nFlags, CPoint point)
+{
+#ifdef GRIDCONTROL_USE_TITLETIPS
+ // EFW - Bug Fix
+ m_TitleTip.Hide(); // hide any titletips
+#endif
+
+ // TRACE0("CGridCtrl::OnLButtonDown\n");
+ // CWnd::OnLButtonDown(nFlags, point);
+
+ SetFocus();
+ m_CurCol = -1;
+ m_bLMouseButtonDown = TRUE;
+ m_LeftClickDownPoint = point;
+ // LUC
+ CCellID cellOriginal;
+ m_LeftClickDownCell = GetCellFromPt(point, TRUE, cellOriginal);
+ if (!IsValid(m_LeftClickDownCell))
+ return;
+ m_CurRow = m_LeftClickDownCell.row;
+
+ // If the SHIFT key is not down, then the start of the selection area should be the
+ // cell just clicked. Otherwise, keep the previous selection-start-cell so the user
+ // can add to their previous cell selections in an intuitive way. If no selection-
+ // start-cell has been specified, then set it's value here and now.
+ if ((nFlags & MK_SHIFT) != MK_SHIFT)
+ m_SelectionStartCell = m_LeftClickDownCell;
+ else
+ {
+ if (!IsValid(m_SelectionStartCell))
+ m_SelectionStartCell = m_idCurrentCell;
+ }
+
+ EndEditing();
+
+ // tell the cell about it
+ CGridCellBase* pCell = GetCell(m_LeftClickDownCell.row, m_LeftClickDownCell.col);
+ if (pCell)
+ pCell->OnClickDown(GetPointClicked( m_LeftClickDownCell.row, m_LeftClickDownCell.col, point));
+
+ // Clicked in the text area? Only then will cell selection work
+ BOOL bInTextArea = FALSE;
+ if (pCell)
+ {
+ CRect rectCell;
+ // LUC
+ //if (GetCellRect(m_LeftClickDownCell.row, m_LeftClickDownCell.col, rectCell) &&
+ // pCell->GetTextRect(rectCell))
+ if (GetCellRect(cellOriginal.row, cellOriginal.col, rectCell) &&
+ pCell->GetTextRect(rectCell))
+ {
+ bInTextArea = rectCell.PtInRect(point);
+ }
+ }
+
+ // If the user clicks on the current cell, then prepare to edit it.
+ // (If the user moves the mouse, then dragging occurs)
+ if (m_LeftClickDownCell == m_idCurrentCell &&
+ !(nFlags & MK_CONTROL) && bInTextArea &&
+ IsCellEditable(m_LeftClickDownCell))
+ {
+ m_MouseMode = MOUSE_PREPARE_EDIT;
+ return;
+ }
+ // If the user clicks on a selected cell, then prepare to drag it.
+ // (If the user moves the mouse, then dragging occurs)
+ else if (IsCellSelected(m_LeftClickDownCell))
+ {
+ SetFocusCell(m_LeftClickDownCell.row, m_LeftClickDownCell.col);
+
+ // If control is pressed then unselect the cell or row (depending on the list mode)
+ if (nFlags & MK_CONTROL)
+ {
+ SetFocusCell(m_LeftClickDownCell);
+ if (GetListMode())
+ SelectRows(m_LeftClickDownCell, TRUE, FALSE);
+ else
+ SelectCells(m_LeftClickDownCell, TRUE, FALSE);
+ return;
+ }
+#ifndef GRIDCONTROL_NO_DRAGDROP
+ else if (m_bAllowDragAndDrop)
+ m_MouseMode = MOUSE_PREPARE_DRAG;
+#endif
+ }
+ else if (m_MouseMode != MOUSE_OVER_COL_DIVIDE &&
+ m_MouseMode != MOUSE_OVER_ROW_DIVIDE)
+ {
+ if (m_LeftClickDownCell.row >= GetFixedRowCount() &&
+ m_LeftClickDownCell.col >= GetFixedColumnCount())
+ {
+ SetFocusCell(m_LeftClickDownCell.row, m_LeftClickDownCell.col);
+ }
+ else
+ SetFocusCell(-1, -1);
+
+ //Don't set focus on any cell if the user clicked on a fixed cell - David Pritchard
+ //if (GetRowCount() > GetFixedRowCount() &&
+ // GetColumnCount() > GetFixedColumnCount())
+ // SetFocusCell(max(m_LeftClickDownCell.row, m_nFixedRows),
+ // max(m_LeftClickDownCell.col, m_nFixedCols));
+ }
+
+ SetCapture();
+
+ if (m_MouseMode == MOUSE_NOTHING)
+ {
+ if (m_bAllowColumnResize && MouseOverColumnResizeArea(point))
+ {
+ if (m_MouseMode != MOUSE_OVER_COL_DIVIDE)
+ {
+#ifndef _WIN32_WCE_NO_CURSOR
+ SetCursor(AfxGetApp()->LoadStandardCursor(IDC_SIZEWE));
+#endif
+ m_MouseMode = MOUSE_OVER_COL_DIVIDE;
+ }
+ }
+ else if (m_bAllowRowResize && MouseOverRowResizeArea(point))
+ {
+ if (m_MouseMode != MOUSE_OVER_ROW_DIVIDE)
+ {
+#ifndef _WIN32_WCE_NO_CURSOR
+ SetCursor(AfxGetApp()->LoadStandardCursor(IDC_SIZENS));
+#endif
+ m_MouseMode = MOUSE_OVER_ROW_DIVIDE;
+ }
+ }
+ // else if (m_MouseMode != MOUSE_NOTHING)
+ //{
+ // SetCursor(AfxGetApp()->LoadStandardCursor(IDC_ARROW));
+ // m_MouseMode = MOUSE_NOTHING;
+ //}
+ }
+
+ if (m_MouseMode == MOUSE_OVER_COL_DIVIDE) // sizing column
+ {
+ m_MouseMode = MOUSE_SIZING_COL;
+
+ // Kludge for if we are over the last column...
+ if (GetColumnWidth(GetColumnCount()-1) < m_nResizeCaptureRange)
+ {
+ CRect VisRect;
+ GetVisibleNonFixedCellRange(VisRect);
+ if (abs(point.x - VisRect.right) < m_nResizeCaptureRange)
+ m_LeftClickDownCell.col = GetColumnCount()-1;
+ }
+
+ CPoint start;
+ if (!GetCellOrigin(0, m_LeftClickDownCell.col, &start))
+ return;
+
+ if( !m_bHiddenColUnhide)
+ {
+ // ignore columns that are hidden and look left towards first visible column
+ BOOL bLookForVisible = TRUE;
+ BOOL bIsCellRightBorder = point.x - start.x >= m_nResizeCaptureRange;
+
+ if( bIsCellRightBorder
+ && m_LeftClickDownCell.col + 1 >= GetColumnCount() )
+ {
+ // clicked on last column's right border
+
+ // if last column is visible, don't do anything
+ if( m_LeftClickDownCell.col >= 0)
+ bLookForVisible = FALSE;
+ }
+
+ if( bLookForVisible)
+ {
+ // clicked on column divider other than last right border
+ BOOL bFoundVisible = FALSE;
+ int iOffset = 1;
+
+ if( bIsCellRightBorder)
+ iOffset = 0;
+
+ while( m_LeftClickDownCell.col - iOffset >= 0)
+ {
+ if( GetColumnWidth( m_LeftClickDownCell.col - iOffset) > 0)
+ {
+ bFoundVisible = TRUE;
+ break;
+ }
+ m_LeftClickDownCell.col--;
+ }
+ if( !bFoundVisible)
+ return;
+ }
+ }
+
+
+ CRect rect;
+ GetClientRect(rect);
+ CRect invertedRect(point.x, rect.top, point.x + 2, rect.bottom);
+
+ CDC* pDC = GetDC();
+ if (pDC)
+ {
+ pDC->InvertRect(&invertedRect);
+ ReleaseDC(pDC);
+ }
+
+ // If we clicked to the right of the colimn divide, then reset the click-down cell
+ // as the cell to the left of the column divide - UNLESS we clicked on the last column
+ // and the last column is teensy (kludge fix)
+ if (point.x - start.x < m_nResizeCaptureRange)
+ {
+ if (m_LeftClickDownCell.col < GetColumnCount()-1 ||
+ GetColumnWidth(GetColumnCount()-1) >= m_nResizeCaptureRange)
+ {
+ if (!GetCellOrigin(0, --m_LeftClickDownCell.col, &start))
+ return;
+ }
+ }
+
+ // Allow a cell resize width no greater than that which can be viewed within
+ // the grid itself
+ int nMaxCellWidth = rect.Width()-GetFixedColumnWidth();
+ rect.left = start.x + 1;
+ rect.right = rect.left + nMaxCellWidth;
+
+ ClientToScreen(rect);
+#ifndef _WIN32_WCE_NO_CURSOR
+ ClipCursor(rect);
+#endif
+ }
+ else if (m_MouseMode == MOUSE_OVER_ROW_DIVIDE) // sizing row
+ {
+ m_MouseMode = MOUSE_SIZING_ROW;
+
+ // Kludge for if we are over the last column...
+ if (GetRowHeight(GetRowCount()-1) < m_nResizeCaptureRange)
+ {
+ CRect VisRect;
+ GetVisibleNonFixedCellRange(VisRect);
+ if (abs(point.y - VisRect.bottom) < m_nResizeCaptureRange)
+ m_LeftClickDownCell.row = GetRowCount()-1;
+ }
+
+ CPoint start;
+ if (!GetCellOrigin(m_LeftClickDownCell, &start))
+ return;
+
+ if( !m_bHiddenRowUnhide)
+ {
+ // ignore rows that are hidden and look up towards first visible row
+ BOOL bLookForVisible = TRUE;
+ BOOL bIsCellBottomBorder = point.y - start.y >= m_nResizeCaptureRange;
+
+ if( bIsCellBottomBorder
+ && m_LeftClickDownCell.row + 1 >= GetRowCount() )
+ {
+ // clicked on last row's bottom border
+
+ // if last row is visible, don't do anything
+ if( m_LeftClickDownCell.row >= 0)
+ bLookForVisible = FALSE;
+ }
+
+ if( bLookForVisible)
+ {
+ // clicked on row divider other than last bottom border
+ BOOL bFoundVisible = FALSE;
+ int iOffset = 1;
+
+ if( bIsCellBottomBorder)
+ iOffset = 0;
+
+ while( m_LeftClickDownCell.row - iOffset >= 0)
+ {
+ if( GetRowHeight( m_LeftClickDownCell.row - iOffset) > 0)
+ {
+ bFoundVisible = TRUE;
+ break;
+ }
+ m_LeftClickDownCell.row--;
+ }
+ if( !bFoundVisible)
+ return;
+ }
+ }
+
+ CRect rect;
+ GetClientRect(rect);
+ CRect invertedRect(rect.left, point.y, rect.right, point.y + 2);
+
+ CDC* pDC = GetDC();
+ if (pDC)
+ {
+ pDC->InvertRect(&invertedRect);
+ ReleaseDC(pDC);
+ }
+
+ // If we clicked below the row divide, then reset the click-down cell
+ // as the cell above the row divide - UNLESS we clicked on the last row
+ // and the last row is teensy (kludge fix)
+ if (point.y - start.y < m_nResizeCaptureRange) // clicked below border
+ {
+ if (m_LeftClickDownCell.row < GetRowCount()-1 ||
+ GetRowHeight(GetRowCount()-1) >= m_nResizeCaptureRange)
+ {
+ if (!GetCellOrigin(--m_LeftClickDownCell.row, 0, &start))
+ return;
+ }
+ }
+
+ int nMaxCellHeight = rect.Height()-GetFixedRowHeight();
+ rect.top = start.y + 1;
+ rect.bottom = rect.top + nMaxCellHeight;
+
+ ClientToScreen(rect);
+
+#ifndef _WIN32_WCE_NO_CURSOR
+ ClipCursor(rect);
+#endif
+ }
+ else
+#ifndef GRIDCONTROL_NO_DRAGDROP
+ if (m_MouseMode != MOUSE_PREPARE_DRAG) // not sizing or editing -- selecting
+#endif
+ {
+ SendMessageToParent(m_LeftClickDownCell.row, m_LeftClickDownCell.col, GVN_SELCHANGING);
+
+ // If Ctrl pressed, save the current cell selection. This will get added
+ // to the new cell selection at the end of the cell selection process
+ m_PrevSelectedCellMap.RemoveAll();
+ if (nFlags & MK_CONTROL)
+ {
+ for (POSITION pos = m_SelectedCellMap.GetStartPosition(); pos != NULL; )
+ {
+ DWORD key;
+ CCellID cell;
+ m_SelectedCellMap.GetNextAssoc(pos, key, (CCellID&)cell);
+ m_PrevSelectedCellMap.SetAt(key, cell);
+ }
+ }
+
+ if (m_LeftClickDownCell.row < GetFixedRowCount())
+ {
+ OnFixedRowClick(m_LeftClickDownCell);
+ if(m_AllowReorderColumn && m_LeftClickDownCell.col >= GetFixedColumnCount())
+ {
+ ResetSelectedRange(); // TODO : This is not the better solution, as we do not see why clicking in column header should reset selection
+ //but the state of selection is instable after drag (at least until someone debugs it), so better clear it allways.
+ m_MouseMode = MOUSE_PREPARE_DRAG;
+ m_CurCol = m_LeftClickDownCell.col;
+ }
+ }
+ else if (m_LeftClickDownCell.col < GetFixedColumnCount())
+ OnFixedColumnClick(m_LeftClickDownCell);
+ else
+ {
+ m_MouseMode = m_bListMode? MOUSE_SELECT_ROW : MOUSE_SELECT_CELLS;
+ OnSelecting(m_LeftClickDownCell);
+
+ m_nTimerID = SetTimer(WM_LBUTTONDOWN, m_nTimerInterval, 0);
+ }
+ }
+ m_LastMousePoint = point;
+}
+
+void CGridCtrl::OnLButtonUp(UINT nFlags, CPoint point)
+{
+ // TRACE0("CGridCtrl::OnLButtonUp\n");
+
+ CWnd::OnLButtonUp(nFlags, point);
+
+ m_bLMouseButtonDown = FALSE;
+
+#ifndef _WIN32_WCE_NO_CURSOR
+ ClipCursor(NULL);
+#endif
+
+ if (GetCapture()->GetSafeHwnd() == GetSafeHwnd())
+ {
+ ReleaseCapture();
+ KillTimer(m_nTimerID);
+ m_nTimerID = 0;
+
+ // LUC
+ m_bExcludeFreezedRowsFromSelection = FALSE;
+ m_bExcludeFreezedColsFromSelection = FALSE;
+ }
+
+ CPoint pointClickedRel;
+ pointClickedRel = GetPointClicked( m_idCurrentCell.row, m_idCurrentCell.col, point);
+
+ // m_MouseMode == MOUSE_PREPARE_EDIT only if user clicked down on current cell
+ // and then didn't move mouse before clicking up (releasing button)
+ if (m_MouseMode == MOUSE_PREPARE_EDIT)
+ {
+ OnEditCell(m_idCurrentCell.row, m_idCurrentCell.col, pointClickedRel, VK_LBUTTON);
+ }
+#ifndef GRIDCONTROL_NO_DRAGDROP
+ // m_MouseMode == MOUSE_PREPARE_DRAG only if user clicked down on a selected cell
+ // and then didn't move mouse before clicking up (releasing button)
+ else if (m_MouseMode == MOUSE_PREPARE_DRAG)
+ {
+ CGridCellBase* pCell = GetCell(m_idCurrentCell.row, m_idCurrentCell.col);
+ if (pCell)
+ pCell->OnClick( GetPointClicked( m_idCurrentCell.row, m_idCurrentCell.col, point) );
+ SendMessageToParent(m_LeftClickDownCell.row, m_LeftClickDownCell.col, NM_CLICK);
+ SendMessageToParent(m_LeftClickDownCell.row, m_LeftClickDownCell.col, GVN_SELCHANGING);
+ ResetSelectedRange();
+ SendMessageToParent(m_idCurrentCell.row, m_idCurrentCell.col, GVN_SELCHANGED);
+ }
+#endif
+ else if (m_MouseMode == MOUSE_SIZING_COL)
+ {
+ CRect rect;
+ GetClientRect(rect);
+ CRect invertedRect(m_LastMousePoint.x, rect.top, m_LastMousePoint.x + 2, rect.bottom);
+
+ CDC* pDC = GetDC();
+ if (pDC)
+ {
+ pDC->InvertRect(&invertedRect);
+ ReleaseDC(pDC);
+ }
+
+ if (m_LeftClickDownPoint != point && (point.x != 0 || point.y != 0)) // 0 pt fix by email1@bierling.net
+ {
+ CPoint start;
+ if (!GetCellOrigin(m_LeftClickDownCell, &start))
+ return;
+
+ int nColumnWidth = __max(point.x - start.x, m_bAllowColHide? 0 : 1);
+
+ SetColumnWidth(m_LeftClickDownCell.col, nColumnWidth);
+ ResetScrollBars();
+ Invalidate();
+ }
+ }
+ else if (m_MouseMode == MOUSE_SIZING_ROW)
+ {
+ CRect rect;
+ GetClientRect(rect);
+ CRect invertedRect(rect.left, m_LastMousePoint.y, rect.right, m_LastMousePoint.y + 2);
+
+ CDC* pDC = GetDC();
+ if (pDC)
+ {
+ pDC->InvertRect(&invertedRect);
+ ReleaseDC(pDC);
+ }
+
+ if (m_LeftClickDownPoint != point && (point.x != 0 || point.y != 0)) // 0 pt fix by email1@bierling.net
+ {
+ CPoint start;
+ if (!GetCellOrigin(m_LeftClickDownCell, &start))
+ return;
+
+ int nRowHeight = __max(point.y - start.y, m_bAllowRowHide? 0 : 1);
+
+ SetRowHeight(m_LeftClickDownCell.row, nRowHeight);
+ ResetScrollBars();
+ Invalidate();
+ }
+ }
+ else
+ {
+ SendMessageToParent(m_idCurrentCell.row, m_idCurrentCell.col, GVN_SELCHANGED);
+
+ CGridCellBase* pCell = GetCell(m_idCurrentCell.row, m_idCurrentCell.col);
+ if (pCell)
+ pCell->OnClick( GetPointClicked( m_idCurrentCell.row, m_idCurrentCell.col, point) );
+ SendMessageToParent(m_LeftClickDownCell.row, m_LeftClickDownCell.col, NM_CLICK);
+ }
+
+ m_MouseMode = MOUSE_NOTHING;
+
+#ifndef _WIN32_WCE_NO_CURSOR
+ SetCursor(AfxGetApp()->LoadStandardCursor(IDC_ARROW));
+#endif
+
+ if (!IsValid(m_LeftClickDownCell))
+ return;
+
+ CWnd *pOwner = GetOwner();
+ if (pOwner && IsWindow(pOwner->m_hWnd))
+ pOwner->PostMessage(WM_COMMAND, MAKELONG(GetDlgCtrlID(), BN_CLICKED),
+ (LPARAM) GetSafeHwnd());
+}
+
+#ifndef _WIN32_WCE
+void CGridCtrl::OnRButtonDown(UINT nFlags, CPoint point)
+{
+ CWnd::OnRButtonDown(nFlags, point);
+ m_bRMouseButtonDown = TRUE;
+
+#ifdef GRIDCONTROL_USE_TITLETIPS
+ TRACE0("Hiding TitleTip\n");
+ m_TitleTip.Hide(); // hide any titletips
+#endif
+}
+
+// EFW - Added to forward right click to parent so that a context
+// menu can be shown without deriving a new grid class.
+void CGridCtrl::OnRButtonUp(UINT nFlags, CPoint point)
+{
+ CWnd::OnRButtonUp(nFlags, point);
+
+ m_bRMouseButtonDown = FALSE;
+
+ CCellID FocusCell;
+ FocusCell = GetCellFromPt(point);
+
+ EndEditing(); // Auto-destroy any InPlaceEdit's
+
+ // If not a valid cell, pass -1 for row and column
+ if(!IsValid(FocusCell))
+ SendMessageToParent(-1, -1, NM_RCLICK);
+ else
+ {
+ SetFocusCell(-1,-1);
+ SetFocusCell(__max(FocusCell.row, m_nFixedRows),
+ __max(FocusCell.col, m_nFixedCols));
+
+ // tell the cell about it
+ CGridCellBase* pCell = GetCell(FocusCell.row, FocusCell.col);
+ if (pCell)
+ pCell->OnRClick( GetPointClicked( FocusCell.row, FocusCell.col, point) );
+
+ SendMessageToParent(FocusCell.row, FocusCell.col, NM_RCLICK);
+ }
+}
+#endif
+
+#if !defined(_WIN32_WCE_NO_PRINTING) && !defined(GRIDCONTROL_NO_PRINTING)
+/////////////////////////////////////////////////////////////////////////////
+// CGridCtrl printing
+
+// EFW - New print margin support functions
+void CGridCtrl::SetPrintMarginInfo(int nHeaderHeight, int nFooterHeight,
+ int nLeftMargin, int nRightMargin, int nTopMargin,
+ int nBottomMargin, int nGap)
+{
+ // If any parameter is -1, keep the existing setting
+ if(nHeaderHeight > -1)
+ m_nHeaderHeight = nHeaderHeight;
+ if(nFooterHeight > -1)
+ m_nFooterHeight = nFooterHeight;
+ if(nLeftMargin > -1)
+ m_nLeftMargin = nLeftMargin;
+ if(nRightMargin > -1)
+ m_nRightMargin = nRightMargin;
+ if(nTopMargin > -1)
+ m_nTopMargin = nTopMargin;
+ if(nBottomMargin > -1)
+ m_nBottomMargin = nBottomMargin;
+ if(nGap > -1)
+ m_nGap = nGap;
+}
+
+void CGridCtrl::GetPrintMarginInfo(int &nHeaderHeight, int &nFooterHeight,
+ int &nLeftMargin, int &nRightMargin, int &nTopMargin,
+ int &nBottomMargin, int &nGap)
+{
+ nHeaderHeight = m_nHeaderHeight;
+ nFooterHeight = m_nFooterHeight;
+ nLeftMargin = m_nLeftMargin;
+ nRightMargin = m_nRightMargin;
+ nTopMargin = m_nTopMargin;
+ nBottomMargin = m_nBottomMargin;
+ nGap = m_nGap;
+}
+
+void CGridCtrl::Print(CPrintDialog* pPrntDialog /*=NULL*/)
+{
+ CDC dc;
+
+ if (pPrntDialog == NULL)
+ {
+ CPrintDialog printDlg(FALSE);
+ if (printDlg.DoModal() != IDOK) // Get printer settings from user
+ return;
+
+ dc.Attach(printDlg.GetPrinterDC()); // attach a printer DC
+ }
+ else
+ dc.Attach(pPrntDialog->GetPrinterDC()); // attach a printer DC
+
+ dc.m_bPrinting = TRUE;
+
+ CString strTitle;
+ strTitle.LoadString(AFX_IDS_APP_TITLE);
+
+ if( strTitle.IsEmpty() )
+ {
+ CWnd *pParentWnd = GetParent();
+ while (pParentWnd)
+ {
+ pParentWnd->GetWindowText(strTitle);
+ if (strTitle.GetLength()) // can happen if it is a CView, CChildFrm has the title
+ break;
+ pParentWnd = pParentWnd->GetParent();
+ }
+ }
+
+ DOCINFO di; // Initialise print doc details
+ memset(&di, 0, sizeof (DOCINFO));
+ di.cbSize = sizeof (DOCINFO);
+ di.lpszDocName = strTitle;
+
+ BOOL bPrintingOK = dc.StartDoc(&di); // Begin a new print job
+
+ CPrintInfo Info;
+ Info.m_rectDraw.SetRect(0,0, dc.GetDeviceCaps(HORZRES), dc.GetDeviceCaps(VERTRES));
+
+ OnBeginPrinting(&dc, &Info); // Initialise printing
+ for (UINT page = Info.GetMinPage(); page <= Info.GetMaxPage() && bPrintingOK; page++)
+ {
+ dc.StartPage(); // begin new page
+ Info.m_nCurPage = page;
+ OnPrint(&dc, &Info); // Print page
+ bPrintingOK = (dc.EndPage() > 0); // end page
+ }
+ OnEndPrinting(&dc, &Info); // Clean up after printing
+
+ if (bPrintingOK)
+ dc.EndDoc(); // end a print job
+ else
+ dc.AbortDoc(); // abort job.
+
+ dc.Detach(); // detach the printer DC
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// CGridCtrl printing overridables - for Doc/View print/print preview framework
+
+// EFW - Various changes in the next few functions to support the
+// new print margins and a few other adjustments.
+void CGridCtrl::OnBeginPrinting(CDC *pDC, CPrintInfo *pInfo)
+{
+ // OnBeginPrinting() is called after the user has committed to
+ // printing by OK'ing the Print dialog, and after the framework
+ // has created a CDC object for the printer or the preview view.
+
+ // This is the right opportunity to set up the page range.
+ // Given the CDC object, we can determine how many rows will
+ // fit on a page, so we can in turn determine how many printed
+ // pages represent the entire document.
+
+// ASSERT(pDC && pInfo);
+ if (!pDC || !pInfo) return;
+
+ // Get a DC for the current window (will be a screen DC for print previewing)
+ CDC *pCurrentDC = GetDC(); // will have dimensions of the client area
+ if (!pCurrentDC) return;
+
+ CSize PaperPixelsPerInch(pDC->GetDeviceCaps(LOGPIXELSX), pDC->GetDeviceCaps(LOGPIXELSY));
+ CSize ScreenPixelsPerInch(pCurrentDC->GetDeviceCaps(LOGPIXELSX), pCurrentDC->GetDeviceCaps(LOGPIXELSY));
+
+ // Create the printer font
+ int nFontSize = -10;
+ CString strFontName = _T("Arial");
+ m_PrinterFont.CreateFont(nFontSize, 0,0,0, FW_NORMAL, 0,0,0, DEFAULT_CHARSET,
+ OUT_CHARACTER_PRECIS, CLIP_CHARACTER_PRECIS, DEFAULT_QUALITY,
+ DEFAULT_PITCH | FF_DONTCARE, strFontName);
+
+ CFont *pOldFont = pDC->SelectObject(&m_PrinterFont);
+
+ // Get the average character width (in GridCtrl units) and hence the margins
+ m_CharSize = pDC->GetTextExtent(_T("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSATUVWXYZ"),52);
+ m_CharSize.cx /= 52;
+ int nMargins = (m_nLeftMargin+m_nRightMargin)*m_CharSize.cx;
+
+ // Get the page sizes (physical and logical)
+ m_PaperSize = CSize(pDC->GetDeviceCaps(HORZRES), pDC->GetDeviceCaps(VERTRES));
+
+ if( m_bWysiwygPrinting)
+ {
+ m_LogicalPageSize.cx = ScreenPixelsPerInch.cx * m_PaperSize.cx / PaperPixelsPerInch.cx * 3 / 4;
+ m_LogicalPageSize.cy = ScreenPixelsPerInch.cy * m_PaperSize.cy / PaperPixelsPerInch.cy * 3 / 4;
+ }
+ else
+ {
+ m_PaperSize = CSize(pDC->GetDeviceCaps(HORZRES), pDC->GetDeviceCaps(VERTRES));
+
+ m_LogicalPageSize.cx = GetVirtualWidth()+nMargins;
+#ifdef _WIN32_WCE
+ m_LogicalPageSize.cy = (m_LogicalPageSize.cx * m_PaperSize.cy) / m_PaperSize.cx;
+#else
+ m_LogicalPageSize.cy = MulDiv(m_LogicalPageSize.cx, m_PaperSize.cy, m_PaperSize.cx);
+#endif
+ }
+
+ m_nPageHeight = m_LogicalPageSize.cy - GetFixedRowHeight()
+ - (m_nHeaderHeight+m_nFooterHeight + 2*m_nGap)*m_CharSize.cy;
+
+ // Get the number of pages. Assumes no row is bigger than the page size.
+ int nTotalRowHeight = 0;
+ m_nNumPages = 1;
+ for (int row = GetFixedRowCount(); row < GetRowCount(); row++)
+ {
+ nTotalRowHeight += GetRowHeight(row);
+ if (nTotalRowHeight > m_nPageHeight) {
+ m_nNumPages++;
+ nTotalRowHeight = GetRowHeight(row);
+ }
+ }
+
+ // now, figure out how many additional pages must print out if rows ARE bigger
+ // than page size
+ int iColumnOffset = 0;
+ int i1;
+ for( i1=0; i1 < GetFixedColumnCount(); i1++)
+ {
+ iColumnOffset += GetColumnWidth( i1);
+ }
+ m_nPageWidth = m_LogicalPageSize.cx - iColumnOffset
+ - nMargins;
+ m_nPageMultiplier = 1;
+
+ if( m_bWysiwygPrinting)
+ {
+ int iTotalRowWidth = 0;
+ for( i1 = GetFixedColumnCount(); i1 < GetColumnCount(); i1++)
+ {
+ iTotalRowWidth += GetColumnWidth( i1);
+ if( iTotalRowWidth > m_nPageWidth)
+ {
+ m_nPageMultiplier++;
+ iTotalRowWidth = GetColumnWidth( i1);
+ }
+ }
+ m_nNumPages *= m_nPageMultiplier;
+ }
+
+ // Set up the print info
+ pInfo->SetMaxPage(m_nNumPages);
+ pInfo->m_nCurPage = 1; // start printing at page# 1
+
+ ReleaseDC(pCurrentDC);
+ pDC->SelectObject(pOldFont);
+}
+
+void CGridCtrl::OnPrint(CDC *pDC, CPrintInfo *pInfo)
+{
+ if (!pDC || !pInfo)
+ return;
+
+ //CRect rcPage(pInfo->m_rectDraw);
+ CFont *pOldFont = pDC->SelectObject(&m_PrinterFont);
+
+ // Set the page map mode to use GridCtrl units, and setup margin
+ pDC->SetMapMode(MM_ANISOTROPIC);
+ pDC->SetWindowExt(m_LogicalPageSize);
+ pDC->SetViewportExt(m_PaperSize);
+ pDC->SetWindowOrg(-m_nLeftMargin * m_CharSize.cx, 0);
+
+ // Header
+ pInfo->m_rectDraw.top = 0;
+ pInfo->m_rectDraw.left = 0;
+ pInfo->m_rectDraw.right = m_LogicalPageSize.cx - (m_nLeftMargin + m_nRightMargin) * m_CharSize.cx;
+ pInfo->m_rectDraw.bottom = m_nHeaderHeight * m_CharSize.cy;
+ PrintHeader(pDC, pInfo);
+ pDC->OffsetWindowOrg(0, -m_nHeaderHeight * m_CharSize.cy);
+
+ // Gap between header and column headings
+ pDC->OffsetWindowOrg(0, -m_nGap * m_CharSize.cy);
+
+ pDC->OffsetWindowOrg(0, -GetFixedRowHeight());
+
+ // We need to find out which row to start printing for this page.
+ int nTotalRowHeight = 0;
+ UINT nNumPages = 1;
+ m_nCurrPrintRow = GetFixedRowCount();
+
+
+ // Not only the row, but we need to figure out column, too
+
+ // Can print 4 pages, where page 1 and 2 represent the same rows but
+ // with different WIDE columns.
+ //
+ // .......
+ // .1 .2 . If representing page 3 --> iPageIfIgnoredWideCols = 2
+ // ....... iWideColPageOffset = 0
+ // .3 .4 . If representing page 2 --> iPageIfIgnoredWideCols = 1
+ // ....... iWideColPageOffset = 1
+
+ int iPageIfIgnoredWideCols = pInfo->m_nCurPage / m_nPageMultiplier;
+ int iWideColPageOffset = pInfo->m_nCurPage - ( iPageIfIgnoredWideCols * m_nPageMultiplier);
+ if( iWideColPageOffset > 0)
+ iPageIfIgnoredWideCols++;
+
+ if( iWideColPageOffset == 0)
+ iWideColPageOffset = m_nPageMultiplier;
+ iWideColPageOffset--;
+
+ // calculate current print row based on iPageIfIgnoredWideCols
+ while( m_nCurrPrintRow < GetRowCount()
+ && (int)nNumPages < iPageIfIgnoredWideCols)
+ {
+ nTotalRowHeight += GetRowHeight(m_nCurrPrintRow);
+ if (nTotalRowHeight > m_nPageHeight) {
+ nNumPages++;
+ if ((int)nNumPages == iPageIfIgnoredWideCols) break;
+ nTotalRowHeight = GetRowHeight(m_nCurrPrintRow);
+ }
+ m_nCurrPrintRow++;
+ }
+
+ m_nPrintColumn = GetFixedColumnCount();
+ int iTotalRowWidth = 0;
+ int i1, i2;
+
+ // now, calculate which print column to start displaying
+ for( i1 = 0; i1 < iWideColPageOffset; i1++)
+ {
+ for( i2 = m_nPrintColumn; i2 < GetColumnCount(); i2++)
+ {
+ iTotalRowWidth += GetColumnWidth( i2);
+ if( iTotalRowWidth > m_nPageWidth)
+ {
+ m_nPrintColumn = i2;
+ iTotalRowWidth = 0;
+ break;
+ }
+ }
+ }
+
+
+ PrintRowButtons( pDC, pInfo); // print row buttons on each page
+ int iColumnOffset = 0;
+ for( i1=0; i1 < GetFixedColumnCount(); i1++)
+ {
+ iColumnOffset += GetColumnWidth( i1);
+ }
+
+ // Print the column headings
+ pInfo->m_rectDraw.bottom = GetFixedRowHeight();
+
+ if( m_nPrintColumn == GetFixedColumnCount())
+ {
+ // have the column headings fcn draw the upper left fixed cells
+ // for the very first columns, only
+ pDC->OffsetWindowOrg( 0, +GetFixedRowHeight());
+
+ m_nPageWidth += iColumnOffset;
+ m_nPrintColumn = 0;
+ PrintColumnHeadings(pDC, pInfo);
+ m_nPageWidth -= iColumnOffset;
+ m_nPrintColumn = GetFixedColumnCount();
+
+ pDC->OffsetWindowOrg( -iColumnOffset, -GetFixedRowHeight());
+ }
+ else
+ {
+ // changed all of this here to match above almost exactly same
+ pDC->OffsetWindowOrg( 0, +GetFixedRowHeight());
+
+ m_nPageWidth += iColumnOffset;
+
+ // print from column 0 ... last column that fits on the current page
+ PrintColumnHeadings(pDC, pInfo);
+
+ m_nPageWidth -= iColumnOffset;
+
+ pDC->OffsetWindowOrg( -iColumnOffset, -GetFixedRowHeight());
+ }
+
+
+ if (m_nCurrPrintRow >= GetRowCount()) return;
+
+ // Draw as many rows as will fit on the printed page.
+ // Clip the printed page so that there is no partially shown
+ // row at the bottom of the page (the same row which will be fully
+ // shown at the top of the next page).
+
+ BOOL bFirstPrintedRow = TRUE;
+ CRect rect;
+ rect.bottom = -1;
+ while (m_nCurrPrintRow < GetRowCount())
+ {
+ rect.top = rect.bottom+1;
+ rect.bottom = rect.top + GetRowHeight(m_nCurrPrintRow) - 1;
+
+ if (rect.bottom > m_nPageHeight) break; // Gone past end of page
+
+ rect.right = -1;
+
+ // modified to allow printing of wide grids on multiple pages
+ for (int col = m_nPrintColumn; col < GetColumnCount(); col++)
+ {
+ rect.left = rect.right+1;
+ rect.right = rect.left
+ + GetColumnWidth( col)
+ - 1;
+
+ if( rect.right > m_nPageWidth)
+ break;
+
+ CGridCellBase* pCell = GetCell(m_nCurrPrintRow, col);
+ if (pCell)
+ pCell->PrintCell(pDC, m_nCurrPrintRow, col, rect);
+
+ if (m_nGridLines == GVL_BOTH || m_nGridLines == GVL_HORZ)
+ {
+ int Overlap = (col == 0)? 0:1;
+ pDC->MoveTo(rect.left-Overlap, rect.bottom);
+ pDC->LineTo(rect.right, rect.bottom);
+ if (m_nCurrPrintRow == 0) {
+ pDC->MoveTo(rect.left-Overlap, rect.top);
+ pDC->LineTo(rect.right, rect.top);
+ }
+ }
+ if (m_nGridLines == GVL_BOTH || m_nGridLines == GVL_VERT)
+ {
+ int Overlap = (bFirstPrintedRow)? 0:1;
+ pDC->MoveTo(rect.right, rect.top-Overlap);
+ pDC->LineTo(rect.right, rect.bottom);
+ if (col == 0) {
+ pDC->MoveTo(rect.left, rect.top-Overlap);
+ pDC->LineTo(rect.left, rect.bottom);
+ }
+ }
+
+ }
+ m_nCurrPrintRow++;
+ bFirstPrintedRow = FALSE;
+ }
+
+
+ // Footer
+ pInfo->m_rectDraw.bottom = m_nFooterHeight * m_CharSize.cy;
+ pDC->SetWindowOrg( -m_nLeftMargin * m_CharSize.cx,
+ -m_LogicalPageSize.cy + m_nFooterHeight * m_CharSize.cy);
+ PrintFooter(pDC, pInfo);
+
+ // SetWindowOrg back for next page
+ pDC->SetWindowOrg(0,0);
+
+ pDC->SelectObject(pOldFont);
+}
+
+
+// added by M.Fletcher 12/17/00
+void CGridCtrl::PrintFixedRowCells(int nStartColumn, int nStopColumn, int& row, CRect& rect,
+ CDC *pDC, BOOL& bFirst)
+{
+ // print all cells from nStartColumn to nStopColumn on row
+ for (int col =nStartColumn; col < nStopColumn; col++)
+ {
+ rect.left = rect.right+1;
+ rect.right = rect.left + GetColumnWidth( col) - 1;
+
+ if( rect.right > m_nPageWidth)
+ break;
+
+ CGridCellBase* pCell = GetCell(row, col);
+ if (pCell)
+ pCell->PrintCell(pDC, row, col, rect);
+
+ if (m_nGridLines == GVL_BOTH || m_nGridLines == GVL_HORZ)
+ {
+ int Overlap = (col == 0)? 0:1;
+
+ pDC->MoveTo(rect.left-Overlap, rect.bottom);
+ pDC->LineTo(rect.right, rect.bottom);
+
+ if (row == 0)
+ {
+ pDC->MoveTo(rect.left-Overlap, rect.top);
+ pDC->LineTo(rect.right, rect.top);
+ }
+ }
+
+ if (m_nGridLines == GVL_BOTH || m_nGridLines == GVL_VERT)
+ {
+ int Overlap = (row == 0)? 0:1;
+
+ pDC->MoveTo(rect.right, rect.top-Overlap);
+ pDC->LineTo(rect.right, rect.bottom);
+
+ if( bFirst)
+ {
+ pDC->MoveTo(rect.left-1, rect.top-Overlap);
+ pDC->LineTo(rect.left-1, rect.bottom);
+ bFirst = FALSE;
+ }
+
+ }
+
+ } // end of column cells loop
+
+
+} // end of CGridCtrl::PrintFixedRowCells
+
+void CGridCtrl::PrintColumnHeadings(CDC *pDC, CPrintInfo* /*pInfo*/)
+{
+ CFont *pOldFont = pDC->SelectObject(&m_PrinterFont);
+
+ CRect rect;
+ rect.bottom = -1;
+
+ BOOL bFirst = TRUE;
+ BOOL bOriginal;
+
+
+ // modified to allow column hdr printing of multi-page wide grids
+ for (int row = 0; row < GetFixedRowCount(); row++)
+ {
+ rect.top = rect.bottom+1;
+ rect.bottom = rect.top + GetRowHeight(row) - 1;
+
+ rect.right = -1;
+
+ // if printColumn > fixedcolumncount we are on page 2 or more
+ // lets printout those fixed cell headings again the 1 or more that would be missed
+ // added by M.Fletcher 12/17/00
+ if(m_nPrintColumn>= GetFixedColumnCount())
+ {
+ bOriginal=bFirst;
+ // lets print the missing fixed cells on left first out to last fixed column
+ PrintFixedRowCells(0,GetFixedColumnCount(), row, rect, pDC, bFirst);
+ bFirst=bOriginal;
+ }
+
+ // now back to normal business print cells in heading after all fixed columns
+ PrintFixedRowCells(m_nPrintColumn, GetColumnCount(), row, rect, pDC, bFirst);
+
+ } // end of Row Loop
+
+ pDC->SelectObject(pOldFont);
+} // end of CGridCtrl::PrintColumnHeadings
+
+
+
+/*****************************************************************************
+Prints line of row buttons on each page of the printout. Assumes that
+the window origin is setup before calling
+
+*****************************************************************************/
+void CGridCtrl::PrintRowButtons(CDC *pDC, CPrintInfo* /*pInfo*/)
+{
+ CFont *pOldFont = pDC->SelectObject(&m_PrinterFont);
+
+ CRect rect;
+ rect.right = -1;
+
+ BOOL bFirst = TRUE;
+ for( int iCol = 0; iCol < GetFixedColumnCount(); iCol++)
+ {
+ rect.left = rect.right+1;
+ rect.right = rect.left
+ + GetColumnWidth( iCol)
+ - 1;
+
+ rect.bottom = -1;
+ for( int iRow = m_nCurrPrintRow; iRow < GetRowCount(); iRow++)
+ {
+ rect.top = rect.bottom+1;
+ rect.bottom = rect.top + GetRowHeight( iRow) - 1;
+
+ if( rect.bottom > m_nPageHeight)
+ break;
+
+ CGridCellBase* pCell = GetCell(iRow, iCol);
+ if (pCell)
+ pCell->PrintCell(pDC, iRow, iCol, rect);
+
+ if (m_nGridLines == GVL_BOTH || m_nGridLines == GVL_HORZ)
+ {
+ int Overlap = (iCol == 0)? 0:1;
+ pDC->MoveTo(rect.left-Overlap, rect.bottom);
+ pDC->LineTo(rect.right, rect.bottom);
+ if( bFirst) {
+ pDC->MoveTo(rect.left-Overlap, rect.top-1);
+ pDC->LineTo(rect.right, rect.top-1);
+ bFirst = FALSE;
+ }
+ }
+ if (m_nGridLines == GVL_BOTH || m_nGridLines == GVL_VERT)
+ {
+ int Overlap = (iRow == 0)? 0:1;
+ pDC->MoveTo(rect.right, rect.top-Overlap);
+ pDC->LineTo(rect.right, rect.bottom);
+ if (iCol == 0) {
+ pDC->MoveTo(rect.left, rect.top-Overlap);
+ pDC->LineTo(rect.left, rect.bottom);
+ }
+ }
+
+ }
+ }
+ pDC->SelectObject(pOldFont);
+}
+
+void CGridCtrl::PrintHeader(CDC *pDC, CPrintInfo *pInfo)
+{
+ // print App title on top right margin
+ CString strRight;
+ strRight.LoadString(AFX_IDS_APP_TITLE);
+
+ // print parent window title in the centre (Gert Rijs)
+ CString strCenter;
+ CWnd *pParentWnd = GetParent();
+ while (pParentWnd)
+ {
+ pParentWnd->GetWindowText(strCenter);
+ if (strCenter.GetLength()) // can happen if it is a CView, CChildFrm has the title
+ break;
+ pParentWnd = pParentWnd->GetParent();
+ }
+
+ CFont BoldFont;
+ LOGFONT lf;
+
+ //create bold font for header and footer
+ VERIFY(m_PrinterFont.GetLogFont(&lf));
+ lf.lfWeight = FW_BOLD;
+ VERIFY(BoldFont.CreateFontIndirect(&lf));
+
+ CFont *pNormalFont = pDC->SelectObject(&BoldFont);
+ int nPrevBkMode = pDC->SetBkMode(TRANSPARENT);
+
+ CRect rc(pInfo->m_rectDraw);
+ if( !strCenter.IsEmpty() )
+ pDC->DrawText( strCenter, &rc, DT_CENTER | DT_SINGLELINE | DT_NOPREFIX | DT_VCENTER);
+ if( !strRight.IsEmpty() )
+ pDC->DrawText( strRight, &rc, DT_RIGHT | DT_SINGLELINE | DT_NOPREFIX | DT_VCENTER);
+
+ pDC->SetBkMode(nPrevBkMode);
+ pDC->SelectObject(pNormalFont);
+ BoldFont.DeleteObject();
+
+ // draw ruled-line across top
+ pDC->SelectStockObject(BLACK_PEN);
+ pDC->MoveTo(rc.left, rc.bottom);
+ pDC->LineTo(rc.right, rc.bottom);
+}
+
+//print footer with a line and date, and page number
+void CGridCtrl::PrintFooter(CDC *pDC, CPrintInfo *pInfo)
+{
+ // page numbering on left
+ CString strLeft;
+ strLeft.Format(_T("Page %d of %d"), pInfo->m_nCurPage, pInfo->GetMaxPage() );
+
+ // date and time on the right
+ CString strRight;
+ COleDateTime t = COleDateTime::GetCurrentTime();
+ strRight = t.Format(_T("%c"));
+
+ CRect rc(pInfo->m_rectDraw);
+
+ // draw ruled line on bottom
+ pDC->SelectStockObject(BLACK_PEN);
+ pDC->MoveTo(rc.left, rc.top);
+ pDC->LineTo(rc.right, rc.top);
+
+ CFont BoldFont;
+ LOGFONT lf;
+
+ //create bold font for header and footer
+ m_PrinterFont.GetLogFont(&lf);
+ lf.lfWeight = FW_BOLD;
+ BoldFont.CreateFontIndirect(&lf);
+
+ CFont *pNormalFont = pDC->SelectObject(&BoldFont);
+ int nPrevBkMode = pDC->SetBkMode(TRANSPARENT);
+
+ // EFW - Bug fix - Force text color to black. It doesn't always
+ // get set to a printable color when it gets here.
+ pDC->SetTextColor(RGB(0, 0, 0));
+
+ if( !strLeft.IsEmpty() )
+ pDC->DrawText( strLeft, &rc, DT_LEFT | DT_SINGLELINE | DT_NOPREFIX | DT_VCENTER);
+ if( !strRight.IsEmpty() )
+ pDC->DrawText( strRight, &rc, DT_RIGHT | DT_SINGLELINE | DT_NOPREFIX | DT_VCENTER);
+
+ pDC->SetBkMode(nPrevBkMode);
+ pDC->SelectObject(pNormalFont);
+ BoldFont.DeleteObject();
+}
+
+void CGridCtrl::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
+{
+ m_PrinterFont.DeleteObject();
+}
+
+#endif // !defined(_WIN32_WCE_NO_PRINTING) && !defined(GRIDCONTROL_NO_PRINTING)
+
+
+#ifndef _WIN32_WCE
+/////////////////////////////////////////////////////////////////////////////
+// CGridCtrl persistance
+
+BOOL CGridCtrl::Save(LPCTSTR filename, TCHAR chSeparator/*=_T(',')*/)
+{
+ CStdioFile File;
+ CFileException ex;
+ CString strSeparator(chSeparator);
+
+ if (!File.Open(filename, CFile::modeWrite | CFile::modeCreate| CFile::typeText, &ex))
+ {
+ ex.ReportError();
+ return FALSE;
+ }
+
+ TRY
+ {
+ int nNumColumns = GetColumnCount();
+ for (int i = 0; i < GetRowCount(); i++)
+ {
+ for (int j = 0; j < nNumColumns; j++)
+ {
+ File.WriteString(GetItemText(i,j));
+ File.WriteString((j==(nNumColumns-1))? _T("\n"): strSeparator);
+ }
+ }
+
+ File.Close();
+ }
+
+ CATCH (CFileException, e)
+ {
+ AfxMessageBox(_T("Unable to save grid list"));
+ return FALSE;
+ }
+ END_CATCH
+
+ return TRUE;
+}
+
+BOOL CGridCtrl::Load(LPCTSTR filename, TCHAR chSeparator/*=_T(',')*/)
+{
+ if (GetVirtualMode())
+ return FALSE;
+
+ TCHAR *token, *end;
+ TCHAR buffer[1024];
+ CStdioFile File;
+ CFileException ex;
+
+ if (!File.Open(filename, CFile::modeRead | CFile::typeText))
+ {
+ ex.ReportError();
+ return FALSE;
+ }
+
+ DeleteAllItems();
+
+ TRY
+ {
+ // Read Header off file
+ File.ReadString(buffer, 1024);
+
+ // Get first token
+ for (token=buffer, end=buffer;
+ *end && (*end != chSeparator) && (*end != _T('\n'));
+ end++)
+ ;
+
+ if ((*end == _T('\0')) && (token == end))
+ token = NULL;
+
+ *end = _T('\0');
+
+ while (token)
+ {
+ InsertColumn(token);
+
+ // Get next token
+ for (token=++end; *end && (*end != chSeparator) && (*end != _T('\n'));
+ end++)
+ ;
+
+ if ((*end == _T('\0')) && (token == end))
+ token = NULL;
+
+ *end = _T('\0');
+ }
+
+ // Read in rest of data
+ int nItem = 1;
+ while (File.ReadString(buffer, 1024))
+ {
+ // Get first token
+ for (token=buffer, end=buffer;
+ *end && (*end != chSeparator) && (*end != _T('\n')); end++)
+ ;
+
+ if ((*end == _T('\0')) && (token == end))
+ token = NULL;
+
+ *end = _T('\0');
+
+ int nSubItem = 0;
+ while (token)
+ {
+ if (!nSubItem)
+ InsertRow(token);
+ else
+ SetItemText(nItem, nSubItem, token);
+
+ // Get next token
+ for (token=++end; *end && (*end != chSeparator) && (*end != _T('\n'));
+ end++)
+ ;
+
+ if ((*end == _T('\0')) && (token == end))
+ token = NULL;
+
+ *end = _T('\0');
+
+ nSubItem++;
+ }
+ nItem++;
+ }
+
+ AutoSizeColumns(GetAutoSizeStyle());
+ File.Close();
+ }
+
+ CATCH (CFileException, e)
+ {
+ AfxMessageBox(_T("Unable to load grid data"));
+ return FALSE;
+ }
+ END_CATCH
+
+ return TRUE;
+}
+#endif
+
+/////////////////////////////////////////////////////////////////////////////
+// CGridCtrl overrideables
+
+#ifndef GRIDCONTROL_NO_DRAGDROP
+// This is no longer needed since I've changed to OLE drag and drop - but it's
+// still cool code. :)
+CImageList* CGridCtrl::CreateDragImage(CPoint *pHotSpot)
+{
+ CDC* pDC = GetDC();
+ if (!pDC)
+ return NULL;
+
+ CRect rect;
+ CCellID cell = GetFocusCell();
+ if (!GetCellRect(cell.row, cell.col, rect))
+ return NULL;
+
+ // Translate coordinate system
+ rect.BottomRight() = CPoint(rect.Width(), rect.Height());
+ rect.TopLeft() = CPoint(0, 0);
+ *pHotSpot = rect.BottomRight();
+
+ // Create a new imagelist (the caller of this function has responsibility
+ // for deleting this list)
+ CImageList* pList = new CImageList;
+ if (!pList || !pList->Create(rect.Width(), rect.Height(), ILC_MASK, 1, 1))
+ {
+ if (pList)
+ delete pList;
+ return NULL;
+ }
+
+ // Create mem DC and bitmap
+ CDC MemDC;
+ CBitmap bm;
+ MemDC.CreateCompatibleDC(pDC);
+ bm.CreateCompatibleBitmap(pDC, rect.Width(), rect.Height());
+ CBitmap* pOldBitmap = MemDC.SelectObject(&bm);
+ MemDC.SetWindowOrg(0, 0);
+
+ // Draw cell onto bitmap in memDC
+ CGridCellBase* pCell = GetCell(cell.row, cell.col);
+ if (pCell)
+ pCell->Draw(&MemDC, cell.row, cell.col, rect, FALSE);
+
+ // Clean up
+ MemDC.SelectObject(pOldBitmap);
+ ReleaseDC(pDC);
+
+ // Add the bitmap we just drew to the image list.
+ pList->Add(&bm, GetDefaultCell(FALSE, FALSE)->GetBackClr());
+ bm.DeleteObject();
+
+ return pList;
+}
+#endif
+
+void CGridCtrl::OnFixedRowClick(CCellID& cell)
+{
+ if (!IsValid(cell))
+ return;
+
+ if (GetHeaderSort())
+ {
+ CWaitCursor waiter;
+ if (cell.col == GetSortColumn())
+ SortItems(cell.col, !GetSortAscending());
+ else
+ SortItems(cell.col, TRUE);
+ Invalidate();
+ }
+
+ // Did the user click on a fixed column cell (so the cell was within the overlap of
+ // fixed row and column cells) - (fix by David Pritchard)
+ if (GetFixedColumnSelection())
+ {
+ if (cell.col < GetFixedColumnCount())
+ {
+ m_MouseMode = MOUSE_SELECT_ALL;
+ OnSelecting(cell);
+ }
+ else
+ {
+ m_MouseMode = MOUSE_SELECT_COL;
+ OnSelecting(cell);
+ }
+ }
+}
+
+void CGridCtrl::OnFixedColumnClick(CCellID& cell)
+{
+ if (!IsValid(cell))
+ return;
+
+// if (m_bListMode && (GetItemState(cell.row, m_nFixedCols) & GVNI_SELECTED))
+// {
+// OnEditCell(cell.row, cell.col, VK_LBUTTON);
+// return;
+// }
+
+ // Did the user click on a fixed row cell (so the cell was within the overlap of
+ // fixed row and column cells) - (fix by David Pritchard)
+ if (GetFixedRowSelection())
+ {
+ if (cell.row < GetFixedRowCount())
+ {
+ m_MouseMode = MOUSE_SELECT_ALL;
+ OnSelecting(cell);
+ }
+ else
+ {
+ m_MouseMode = MOUSE_SELECT_ROW;
+ OnSelecting(cell);
+ }
+ }
+}
+
+// Gets the extent of the text pointed to by str (no CDC needed)
+// By default this uses the selected font (which is a bigger font)
+CSize CGridCtrl::GetTextExtent(int nRow, int nCol, LPCTSTR str)
+{
+ CGridCellBase* pCell = GetCell(nRow, nCol);
+ if (!pCell)
+ return CSize(0, 0);
+ else
+ return pCell->GetTextExtent(str);
+}
+
+// virtual
+void CGridCtrl::OnEditCell(int nRow, int nCol, CPoint point, UINT nChar)
+{
+#ifndef GRIDCONTROL_NO_TITLETIPS
+ m_TitleTip.Hide(); // hide any titletips
+#endif
+
+ // Can we do it?
+ CCellID cell(nRow, nCol);
+ if (!IsValid(cell) || !IsCellEditable(nRow, nCol))
+ return;
+
+ // Can we see what we are doing?
+ EnsureVisible(nRow, nCol);
+ if (!IsCellVisible(nRow, nCol))
+ return;
+
+ // Where, exactly, are we gonna do it??
+ CRect rect;
+ if (!GetCellRect(cell, rect))
+ return;
+
+ // Check we can edit...
+ if (SendMessageToParent(nRow, nCol, GVN_BEGINLABELEDIT) >= 0)
+ {
+ // LUC
+ GetTopLeftMergedCell(nRow, nCol, rect);
+
+ // Let's do it...
+ CGridCellBase* pCell = GetCell(nRow, nCol);
+ if (pCell)
+ {
+ pCell->Edit(nRow, nCol, rect, point, IDC_INPLACE_CONTROL, nChar);
+ }
+
+ }
+}
+
+// virtual
+void CGridCtrl::EndEditing()
+{
+ CCellID cell = GetFocusCell();
+ if (!IsValid(cell)) return;
+ CGridCellBase *pCell = GetCell(cell.row, cell.col);
+ if (pCell)
+ pCell->EndEdit();
+}
+
+// virtual
+void CGridCtrl::OnEndEditCell(int nRow, int nCol, CString str)
+{
+ CString strCurrentText = GetItemText(nRow, nCol);
+ if (strCurrentText != str)
+ {
+ SetItemText(nRow, nCol, str);
+ if (ValidateEdit(nRow, nCol, str) &&
+ SendMessageToParent(nRow, nCol, GVN_ENDLABELEDIT) >= 0)
+ {
+ SetModified(TRUE, nRow, nCol);
+ RedrawCell(nRow, nCol);
+ }
+ else
+ {
+ SetItemText(nRow, nCol, strCurrentText);
+ }
+ }
+
+ CGridCellBase* pCell = GetCell(nRow, nCol);
+ if (pCell)
+ pCell->OnEndEdit();
+}
+
+// If this returns FALSE then the editing isn't allowed
+// virtual
+BOOL CGridCtrl::ValidateEdit(int nRow, int nCol, LPCTSTR str)
+{
+ CGridCellBase* pCell = GetCell(nRow, nCol);
+// ASSERT(pCell);
+ if (!pCell)
+ return TRUE;
+
+ return pCell->ValidateEdit(str);
+}
+
+// virtual
+CString CGridCtrl::GetItemText(int nRow, int nCol) const
+{
+ if (nRow < 0 || nRow >= m_nRows || nCol < 0 || nCol >= m_nCols)
+ return _T("");
+
+ CGridCellBase* pCell = GetCell(nRow, nCol);
+// ASSERT(pCell);
+ if (!pCell)
+ return _T("");
+
+ return pCell->GetText();
+}
+
+void CGridCtrl::ResetVirtualOrder()
+{
+ m_arRowOrder.resize(m_nRows);
+ for (int i = 0; i < m_nRows; i++)
+ {
+ m_arRowOrder[i] = i;
+ }
+}
+
+
+void CGridCtrl::Reorder(int From, int To)
+{
+ // Set line From just after Line To
+// ASSERT(From>= GetFixedRowCount() && To>=GetFixedRowCount()-1 && From<m_nRows && To<m_nRows);
+ int Value = m_arRowOrder[From];
+ m_arRowOrder.erase(m_arRowOrder.begin()+From);
+ int Offset = (From>=To ? 1:0);
+ m_arRowOrder.insert(m_arRowOrder.begin()+To+Offset, Value);
+
+}
+
+
+// LUC
+INT_PTR CGridCtrl::MergeCells(CCellRange& mergedCellRange)
+{
+ INT_PTR nMergeID = -1;
+ if(IsValid(mergedCellRange))
+ {
+ m_arMergedCells.Add(mergedCellRange);
+ nMergeID = m_arMergedCells.GetSize() - 1;
+ }
+
+ return nMergeID;
+
+}
+
+void CGridCtrl::SplitCells(INT_PTR nMergeID)
+{
+ if(nMergeID > -1)
+ {
+ m_arMergedCells.RemoveAt(nMergeID);
+ }
+}
+
+BOOL CGridCtrl::IsMergedCell(int row, int col, CCellRange& mergedCellRange)
+{
+ if((mergedCellRange.GetMinRow() <= row) && (mergedCellRange.GetMinCol() <= col)
+ && (mergedCellRange.GetMaxRow() >= row) && (mergedCellRange.GetMaxCol() >= col))
+ {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+BOOL CGridCtrl::GetMergedCellRect(CCellRange& mergedCell, CRect& rect)
+{
+ CCellID idTopLeftMin = GetTopleftNonFixedCell();
+
+ if(m_nFreezedRows > 0)
+ {
+ idTopLeftMin.row = m_nFixedRows;
+ }
+ if(m_nFreezedCols > 0)
+ {
+ idTopLeftMin.col = m_nFixedCols;
+ }
+
+ int nMinRow = mergedCell.GetMinRow();
+ if(nMinRow < idTopLeftMin.row)
+ nMinRow = idTopLeftMin.row;
+
+ int nMinCol = mergedCell.GetMinCol();
+ if(nMinCol < idTopLeftMin.col)
+ nMinCol = idTopLeftMin.col;
+
+ int nMaxRow = mergedCell.GetMaxRow();
+ int nMaxCol = mergedCell.GetMaxCol();
+
+ while(!IsCellVisible(nMinRow, nMaxCol))
+ {
+ nMaxCol--;
+ if(nMaxCol <= nMinCol)
+ {
+ break;
+ }
+ }
+
+ while(!IsCellVisible(nMaxRow, nMinCol))
+ {
+ nMaxRow--;
+ if(nMaxRow <= nMinRow)
+ {
+ break;
+ }
+ }
+
+ CRect rcTopLeft;
+ GetCellRect(nMinRow, nMinCol, rcTopLeft);
+
+ CRect rcBottomRight;
+ GetCellRect(nMaxRow, nMaxCol, rcBottomRight);
+
+ rect.left = rcTopLeft.left;
+ rect.top = rcTopLeft.top;
+ rect.right = rcBottomRight.right;
+ rect.bottom = rcBottomRight.bottom;
+
+ return TRUE;
+}
+
+BOOL CGridCtrl::GetTopLeftMergedCell(int& row, int& col, CRect& mergeRect)
+{
+ BOOL bRet = FALSE;
+
+ INT_PTR size = m_arMergedCells.GetSize();
+ if(size > 0)
+ {
+ for(INT_PTR i = 0; i < size; i++)
+ {
+ CCellRange& mergedCell = m_arMergedCells[i];
+ if(IsMergedCell(row, col, mergedCell))
+ {
+ CCellID idTopLeftMin = GetTopleftNonFixedCell();
+
+ if(m_nFreezedRows > 0)
+ {
+ idTopLeftMin.row = m_nFixedRows;
+ }
+ if(m_nFreezedCols > 0)
+ {
+ idTopLeftMin.col = m_nFixedCols;
+ }
+
+ int nMinRow = mergedCell.GetMinRow();
+ int nMinCol = mergedCell.GetMinCol();
+
+ row = nMinRow;
+ col = nMinCol;
+
+ if(nMinRow < idTopLeftMin.row)
+ nMinRow = idTopLeftMin.row;
+
+ if(nMinCol < idTopLeftMin.col)
+ nMinCol = idTopLeftMin.col;
+
+ int nMaxRow = mergedCell.GetMaxRow();
+ int nMaxCol = mergedCell.GetMaxCol();
+
+ while(!IsCellVisible(nMinRow, nMaxCol))
+ {
+ nMaxCol--;
+ if(nMaxCol <= nMinCol)
+ {
+ break;
+ }
+ }
+
+ while(!IsCellVisible(nMaxRow, nMinCol))
+ {
+ nMaxRow--;
+ if(nMaxRow <= nMinRow)
+ {
+ break;
+ }
+ }
+
+ if(mergeRect != rectNull)
+ {
+ CRect rcTopLeft;
+ GetCellRect(nMinRow, nMinCol, rcTopLeft);
+
+ CRect rcBottomRight;
+ GetCellRect(nMaxRow, nMaxCol, rcBottomRight);
+
+ mergeRect.left = rcTopLeft.left;
+ mergeRect.top = rcTopLeft.top;
+ mergeRect.right = rcBottomRight.right;
+ mergeRect.bottom = rcBottomRight.bottom;
+ }
+
+ bRet = TRUE;
+ }
+ }
+ }
+
+ return bRet;
+}
+
+BOOL CGridCtrl::GetBottomRightMergedCell(int& row, int& col, CRect& mergeRect)
+{
+ BOOL bRet = FALSE;
+
+ INT_PTR size = m_arMergedCells.GetSize();
+ if(size > 0)
+ {
+ for(INT_PTR i = 0; i < size; i++)
+ {
+ CCellRange& mergedCell = m_arMergedCells[i];
+ if(IsMergedCell(row, col, mergedCell))
+ {
+ CCellID idTopLeftMin = GetTopleftNonFixedCell();
+
+ if(m_nFreezedRows > 0)
+ {
+ idTopLeftMin.row = m_nFixedRows;
+ }
+ if(m_nFreezedCols > 0)
+ {
+ idTopLeftMin.col = m_nFixedCols;
+ }
+
+ int nMinRow = mergedCell.GetMinRow();
+ int nMinCol = mergedCell.GetMinCol();
+
+ if(nMinRow < idTopLeftMin.row)
+ nMinRow = idTopLeftMin.row;
+
+ if(nMinCol < idTopLeftMin.col)
+ nMinCol = idTopLeftMin.col;
+
+ int nMaxRow = mergedCell.GetMaxRow();
+ int nMaxCol = mergedCell.GetMaxCol();
+
+ row = nMaxRow;
+ col = nMaxCol;
+
+ while(!IsCellVisible(nMinRow, nMaxCol))
+ {
+ nMaxCol--;
+ if(nMaxCol <= nMinCol)
+ {
+ break;
+ }
+ }
+
+ while(!IsCellVisible(nMaxRow, nMinCol))
+ {
+ nMaxRow--;
+ if(nMaxRow <= nMinRow)
+ {
+ break;
+ }
+ }
+
+ if(mergeRect != rectNull)
+ {
+ CRect rcTopLeft;
+ GetCellRect(nMinRow, nMinCol, rcTopLeft);
+
+ CRect rcBottomRight;
+ GetCellRect(nMaxRow, nMaxCol, rcBottomRight);
+
+ mergeRect.left = rcTopLeft.left;
+ mergeRect.top = rcTopLeft.top;
+ mergeRect.right = rcBottomRight.right;
+ mergeRect.bottom = rcBottomRight.bottom;
+ }
+
+ bRet = TRUE;
+ }
+ }
+ }
+
+ return bRet;
+}
+
+
+BOOL CGridCtrl::GetMergedCellRect(int row, int col, CRect& rect)
+{
+ INT_PTR size = m_arMergedCells.GetSize();
+ if(size > 0)
+ {
+ for(INT_PTR i = 0; i < size; i++)
+ {
+ if(IsMergedCell(row, col, m_arMergedCells[i]))
+ {
+ CCellID idTopLeftMin = GetTopleftNonFixedCell();
+
+ int nMinRow = m_arMergedCells[i].GetMinRow();
+ if(nMinRow < idTopLeftMin.row)
+ nMinRow = idTopLeftMin.row;
+ int nMinCol = m_arMergedCells[i].GetMinCol();
+ if(nMinCol < idTopLeftMin.col)
+ nMinCol = idTopLeftMin.col;
+ int nMaxRow = m_arMergedCells[i].GetMaxRow();
+ int nMaxCol = m_arMergedCells[i].GetMaxCol();
+
+ CRect rcTopLeft;
+ GetCellRect(nMinRow, nMinCol, rcTopLeft);
+
+ CRect rcBottomRight;
+ GetCellRect(nMaxRow, nMaxCol, rcBottomRight);
+
+ rect.left = rcTopLeft.left;
+ rect.top = rcTopLeft.top;
+ rect.right = rcBottomRight.right;
+ rect.bottom = rcBottomRight.bottom;
+
+ return TRUE;
+ }
+ }
+ }
+
+ return FALSE;
+}
+
+// LUC
+BOOL CGridCtrl::IsFocused(CGridCellBase& cell, int nRow, int nCol)
+{
+ BOOL bRet = cell.IsFocused();
+ if(!bRet && m_bDrawingMergedCell)
+ {
+ CCellRange& mergedCell = m_arMergedCells[m_nCurrentMergeID];
+ for(int row = mergedCell.GetMinRow(); row <= mergedCell.GetMaxRow(); row++)
+ {
+ for(int col = mergedCell.GetMinCol(); col <= mergedCell.GetMaxCol(); col++)
+ {
+ CGridCellBase* pCell = GetCell(row, col);
+ if(pCell != NULL)
+ {
+ if(pCell->IsFocused())
+ {
+ bRet = TRUE;
+ }
+ }
+ }
+ }
+ }
+
+ return bRet;
+}
+
+BOOL CGridCtrl::IsSelected(CGridCellBase& cell, int nRow, int nCol)
+{
+ BOOL bRet = cell.IsSelected();
+ if(!bRet && m_bDrawingMergedCell)
+ {
+ CCellRange& mergedCell = m_arMergedCells[m_nCurrentMergeID];
+ for(int row = mergedCell.GetMinRow(); row <= mergedCell.GetMaxRow(); row++)
+ {
+ for(int col = mergedCell.GetMinCol(); col <= mergedCell.GetMaxCol(); col++)
+ {
+ CGridCellBase* pCell = GetCell(row, col);
+ if(pCell != NULL)
+ {
+ if(pCell->IsSelected())
+ {
+ bRet = TRUE;
+ }
+ }
+ }
+ }
+ }
+
+ return bRet;
+}
\ No newline at end of file
diff --git a/SourceCode/Bond/Servo/GridControl/GridCtrl.h b/SourceCode/Bond/Servo/GridControl/GridCtrl.h
new file mode 100644
index 0000000..84dd980
--- /dev/null
+++ b/SourceCode/Bond/Servo/GridControl/GridCtrl.h
@@ -0,0 +1,1090 @@
+/////////////////////////////////////////////////////////////////////////////
+// GridCtrl.h : header file
+//
+// MFC Grid Control - main header
+//
+// Written by Chris Maunder <chris@codeproject.com>
+// Copyright (c) 1998-2005. All Rights Reserved.
+//
+// This code may be used in compiled form in any way you desire. This
+// file may be redistributed unmodified by any means PROVIDING it is
+// not sold for profit without the authors written consent, and
+// providing that this notice and the authors name and all copyright
+// notices remains intact.
+//
+// An email letting me know how you are using it would be nice as well.
+//
+// This file is provided "as is" with no expressed or implied warranty.
+// The author accepts no liability for any damage/loss of business that
+// this product may cause.
+//
+// For use with CGridCtrl v2.20+
+//
+//////////////////////////////////////////////////////////////////////
+
+// FEATURES BY Mukit, Ataul (2007-11-17):
+// 1. Merge Cell
+// 2. Ability to do XL Style Freeze Pane
+// 3. The Horizontal Gray Area Removed
+
+// FINDINGS:
+// 1. A cell cannot be edited if a tooltip is shown..
+// 2. The InplaceEditCtrl is not multiline even if a cell can contain Multiline Text..
+// 3. If a cell is too small, the InplaceEditCtrl is almost invisible..
+
+#if !defined(AFX_GRIDCTRL_H__519FA702_722C_11D1_ABBA_00A0243D1382__INCLUDED_)
+#define AFX_GRIDCTRL_H__519FA702_722C_11D1_ABBA_00A0243D1382__INCLUDED_
+
+#if _MSC_VER >= 1000
+#pragma once
+#endif // _MSC_VER >= 1000
+
+#include "CellRange.h"
+#include "GridCell.h"
+#include <afxtempl.h>
+#include <vector>
+using namespace std;
+
+
+struct CELL_ENABLE
+{
+ CELL_ENABLE()
+ {
+ nEnable = -1;
+ }
+ void SetEnable(BOOL bValue)
+ {
+ nEnable = bValue;
+ }
+ BOOL isEnable()
+ {
+ if (nEnable > 0)
+ {
+ return TRUE;
+ }
+ else
+ {
+ return FALSE;
+ }
+ }
+ BOOL isActivated()
+ {
+ if (nEnable < 0)
+ {
+ return FALSE;
+ }
+ else
+ {
+ return TRUE;
+ }
+ }
+ int nEnable;
+};
+
+///////////////////////////////////////////////////////////////////////////////////
+// Defines - these determine the features (and the final size) of the final code
+///////////////////////////////////////////////////////////////////////////////////
+
+//#define GRIDCONTROL_NO_TITLETIPS // Do not use titletips for cells with large data
+//#define GRIDCONTROL_NO_DRAGDROP // Do not use OLE drag and drop
+//#define GRIDCONTROL_NO_CLIPBOARD // Do not use clipboard routines
+
+#ifdef _WIN32_WCE
+# define GRIDCONTROL_NO_TITLETIPS // Do not use titletips for cells with large data
+# define GRIDCONTROL_NO_DRAGDROP // Do not use OLE drag and drop
+# define GRIDCONTROL_NO_CLIPBOARD // Do not use clipboard routines
+# define GRIDCONTROL_NO_PRINTING // Do not use printing routines
+# ifdef WCE_NO_PRINTING // Older versions of CE had different #def's
+# define _WIN32_WCE_NO_PRINTING
+# endif
+# ifdef WCE_NO_CURSOR
+# define _WIN32_WCE_NO_CURSOR
+# endif
+#endif // _WIN32_WCE
+
+// Use this as the classname when inserting this control as a custom control
+// in the MSVC++ dialog editor
+#define GRIDCTRL_CLASSNAME _T("MFCGridCtrl") // Window class name
+#define IDC_INPLACE_CONTROL 8 // ID of inplace edit controls
+
+
+///////////////////////////////////////////////////////////////////////////////////
+// Conditional includes
+///////////////////////////////////////////////////////////////////////////////////
+
+#ifndef GRIDCONTROL_NO_TITLETIPS
+# include "TitleTip.h"
+#endif
+
+#ifndef GRIDCONTROL_NO_DRAGDROP
+# include "GridDropTarget.h"
+# undef GRIDCONTROL_NO_CLIPBOARD // Force clipboard functions on
+#endif
+
+#ifndef GRIDCONTROL_NO_CLIPBOARD
+# include <afxole.h>
+#endif
+
+
+///////////////////////////////////////////////////////////////////////////////////
+// Helper functions
+///////////////////////////////////////////////////////////////////////////////////
+
+// Handy functions
+#define IsSHIFTpressed() ( (GetKeyState(VK_SHIFT) & (1 << (sizeof(SHORT)*8-1))) != 0 )
+#define IsCTRLpressed() ( (GetKeyState(VK_CONTROL) & (1 << (sizeof(SHORT)*8-1))) != 0 )
+
+// Backwards compatibility for pre 2.20 grid versions
+#define DDX_GridControl(pDX, nIDC, rControl) DDX_Control(pDX, nIDC, rControl)
+
+
+///////////////////////////////////////////////////////////////////////////////////
+// Structures
+///////////////////////////////////////////////////////////////////////////////////
+
+// This structure sent to Grid's parent in a WM_NOTIFY message
+typedef struct tagNM_GRIDVIEW {
+ NMHDR hdr;
+ int iRow;
+ int iColumn;
+} NM_GRIDVIEW;
+
+// This is sent to the Grid from child in-place edit controls
+typedef struct tagGV_DISPINFO {
+ NMHDR hdr;
+ GV_ITEM item;
+} GV_DISPINFO;
+
+// This is sent to the Grid from child in-place edit controls
+typedef struct tagGV_CACHEHINT {
+ NMHDR hdr;
+ CCellRange range;
+} GV_CACHEHINT;
+
+// storage typedef for each row in the grid
+typedef CTypedPtrArray<CObArray, CGridCellBase*> GRID_ROW;
+
+// For virtual mode callback
+typedef BOOL (CALLBACK* GRIDCALLBACK)(GV_DISPINFO *, LPARAM);
+
+///////////////////////////////////////////////////////////////////////////////////
+// Defines
+///////////////////////////////////////////////////////////////////////////////////
+
+// Grid line/scrollbar selection
+#define GVL_NONE 0L // Neither
+#define GVL_HORZ 1L // Horizontal line or scrollbar
+#define GVL_VERT 2L // Vertical line or scrollbar
+#define GVL_BOTH 3L // Both
+
+// Autosizing option
+#define GVS_DEFAULT 0
+#define GVS_HEADER 1 // Size using column fixed cells data only
+#define GVS_DATA 2 // Size using column non-fixed cells data only
+#define GVS_BOTH 3 // Size using column fixed and non-fixed
+
+// Cell Searching options
+#define GVNI_FOCUSED 0x0001
+#define GVNI_SELECTED 0x0002
+#define GVNI_DROPHILITED 0x0004
+#define GVNI_READONLY 0x0008
+#define GVNI_FIXED 0x0010
+#define GVNI_MODIFIED 0x0020
+// LUC
+#define GVNI_FREEZED 0x0040
+
+#define GVNI_ABOVE LVNI_ABOVE
+#define GVNI_BELOW LVNI_BELOW
+#define GVNI_TOLEFT LVNI_TOLEFT
+#define GVNI_TORIGHT LVNI_TORIGHT
+#define GVNI_ALL (LVNI_BELOW|LVNI_TORIGHT|LVNI_TOLEFT)
+#define GVNI_AREA (LVNI_BELOW|LVNI_TORIGHT)
+
+// Hit test values (not yet implemented)
+#define GVHT_DATA 0x0000
+#define GVHT_TOPLEFT 0x0001
+#define GVHT_COLHDR 0x0002
+#define GVHT_ROWHDR 0x0004
+#define GVHT_COLSIZER 0x0008
+#define GVHT_ROWSIZER 0x0010
+#define GVHT_LEFT 0x0020
+#define GVHT_RIGHT 0x0040
+#define GVHT_ABOVE 0x0080
+#define GVHT_BELOW 0x0100
+
+// Messages sent to the grid's parent (More will be added in future)
+#define GVN_BEGINDRAG LVN_BEGINDRAG // LVN_FIRST-9
+#define GVN_BEGINLABELEDIT LVN_BEGINLABELEDIT // LVN_FIRST-5
+#define GVN_BEGINRDRAG LVN_BEGINRDRAG
+#define GVN_COLUMNCLICK LVN_COLUMNCLICK
+#define GVN_DELETEITEM LVN_DELETEITEM
+#define GVN_ENDLABELEDIT LVN_ENDLABELEDIT // LVN_FIRST-6
+#define GVN_SELCHANGING LVN_ITEMCHANGING
+#define GVN_SELCHANGED LVN_ITEMCHANGED
+#define GVN_GETDISPINFO LVN_GETDISPINFO
+#define GVN_ODCACHEHINT LVN_ODCACHEHINT
+#define GVN_COMBOSELCHANGE LVN_FIRST-10
+
+class CGridCtrl;
+
+/////////////////////////////////////////////////////////////////////////////
+// CGridCtrl window
+
+typedef bool (*PVIRTUALCOMPARE)(int, int);
+
+class CGridCtrl : public CWnd
+{
+ DECLARE_DYNCREATE(CGridCtrl)
+ friend class CGridCell;
+ friend class CGridCellBase;
+
+// Construction
+public:
+ CGridCtrl(int nRows = 0, int nCols = 0, int nFixedRows = 0, int nFixedCols = 0);
+
+ BOOL Create(const RECT& rect, CWnd* parent, UINT nID,
+ DWORD dwStyle = WS_CHILD | WS_BORDER | WS_TABSTOP | WS_VISIBLE);
+
+///////////////////////////////////////////////////////////////////////////////////
+// Attributes
+///////////////////////////////////////////////////////////////////////////////////
+public:
+
+///// LUC ///////////////////////////////////////////////////////////////////////
+
+ //// LUC : MergeCell////////
+
+ INT_PTR MergeCells(CCellRange& mergedCellRange);
+ void SplitCells(INT_PTR nMergeID);
+
+ BOOL IsMergedCell(int row, int col, CCellRange& mergedCellRange);
+ BOOL GetMergedCellRect(int row, int col, CRect& rect);
+ BOOL GetMergedCellRect(CCellRange& mergedCell, CRect& rect);
+ BOOL GetTopLeftMergedCell(int& row, int& col, CRect& mergeRect);
+ BOOL GetBottomRightMergedCell(int& row, int& col, CRect& mergeRect);
+ virtual BOOL IsFocused(CGridCellBase& cell, int nRow, int nCol);
+ virtual BOOL IsSelected(CGridCellBase& cell, int nRow, int nCol);
+
+ BOOL m_bDrawingMergedCell;
+ INT_PTR m_nCurrentMergeID;
+
+ static CRect rectNull;
+ static CCellID cellNull;
+
+ // LUC : Freeze Rows
+
+ BOOL SetFreezedRowCount(int nFreezedRows)
+ {
+ BOOL bRet = FALSE;
+ if( (nFreezedRows >= 0) && ((nFreezedRows + m_nFixedRows) <= m_nRows) )
+ {
+ m_nFreezedRows = nFreezedRows;
+ ResetScrollBars();
+ Refresh();
+ bRet = TRUE;
+ }
+
+ return bRet;
+
+ }
+
+ BOOL SetFreezedColumnCount(int nFreezedCols)
+ {
+ BOOL bRet = FALSE;
+ if( (nFreezedCols >= 0) && ((nFreezedCols + m_nFixedCols) <= m_nCols) )
+ {
+ m_nFreezedCols = nFreezedCols;
+ ResetScrollBars();
+ Refresh();
+ bRet = TRUE;
+ }
+
+ return bRet;
+ }
+
+ // To avoid calling ResetScrollBars twice you can use SetFreezedFrame
+ BOOL SetFreezedFrame(int nFreezedRows, int nFreezedCols)
+ {
+ BOOL bRet = FALSE;
+ if( (nFreezedRows >= 0) && ((nFreezedRows + m_nFixedRows) <= m_nRows) )
+ {
+ m_nFreezedRows = nFreezedRows;
+ bRet = TRUE;
+ }
+ if( (nFreezedCols >= 0) && ((nFreezedCols + m_nFixedCols) <= m_nCols) )
+ {
+ m_nFreezedCols = nFreezedCols;
+ bRet = TRUE;
+ }
+ else
+ {
+ bRet = FALSE;
+ }
+
+ ResetScrollBars();
+
+ return bRet;
+ }
+
+ int GetFreezedRowCount() const { return m_nFreezedRows; }
+ int GetFreezedColumnCount() const { return m_nFreezedCols; }
+
+ void ShowHorzNonGridArea(BOOL bShow)
+ {
+ m_bShowHorzNonGridArea = bShow;
+ }
+
+ BOOL IsShowingHorzNonGridArea()
+ {
+ return m_bShowHorzNonGridArea;
+ }
+
+///////////////////////////////////////////////////////////////////////////////////////
+
+ int GetRowCount() const { return m_nRows; }
+ int GetColumnCount() const { return m_nCols; }
+ int GetFixedRowCount(BOOL bIncludeFreezedRows = FALSE) const
+ {
+ return (bIncludeFreezedRows) ? (m_nFixedRows + m_nFreezedRows) : m_nFixedRows;
+ }
+ int GetFixedColumnCount(BOOL bIncludeFreezedCols = FALSE) const
+ {
+ return (bIncludeFreezedCols) ? (m_nFixedCols + m_nFreezedCols) : m_nFixedCols;
+ }
+
+ BOOL SetRowCount(int nRows = 10);
+ BOOL SetColumnCount(int nCols = 10);
+
+ BOOL UpdateCellEditableMask();
+
+ BOOL SetFixedRowCount(int nFixedRows = 1);
+ BOOL SetFixedColumnCount(int nFixedCols = 1);
+
+public:
+ int GetRowHeight(int nRow) const;
+ BOOL SetRowHeight(int row, int height);
+ int GetColumnWidth(int nCol) const;
+ BOOL SetColumnWidth(int col, int width);
+
+ BOOL GetCellOrigin(int nRow, int nCol, LPPOINT p);
+ BOOL GetCellOrigin(const CCellID& cell, LPPOINT p);
+ BOOL GetCellRect(int nRow, int nCol, LPRECT pRect);
+ BOOL GetCellRect(const CCellID& cell, LPRECT pRect);
+
+ BOOL GetTextRect(const CCellID& cell, LPRECT pRect);
+ BOOL GetTextRect(int nRow, int nCol, LPRECT pRect);
+
+ BOOL SetCellMaskEditable(int nRow, int nCol, BOOL bEditable);
+ BOOL isCellMaskEditable(int nRow, int nCol);
+ BOOL isCellMaskActivated(int nRow, int nCol);
+
+ // LUC
+ // Change for MergeCell
+ CCellID GetCellFromPt(CPoint point, BOOL bAllowFixedCellCheck = TRUE, CCellID& cellOriginal = cellNull);
+
+ // LUC
+ //int GetFixedRowHeight() const;
+ //int GetFixedColumnWidth() const;
+ int GetFixedRowHeight(BOOL bIncludeFreezedRows = FALSE) const;
+ int GetFixedColumnWidth(BOOL bIncludeFreezedCols = FALSE) const;
+
+ long GetVirtualWidth() const;
+ long GetVirtualHeight() const;
+
+ CSize GetTextExtent(int nRow, int nCol, LPCTSTR str);
+ // EFW - Get extent of current text in cell
+ inline CSize GetCellTextExtent(int nRow, int nCol) { return GetTextExtent(nRow, nCol, GetItemText(nRow,nCol)); }
+
+ void SetGridBkColor(COLORREF clr) { m_crGridBkColour = clr; }
+ COLORREF GetGridBkColor() const { return m_crGridBkColour; }
+ void SetGridLineColor(COLORREF clr) { m_crGridLineColour = clr; }
+ COLORREF GetGridLineColor() const { return m_crGridLineColour; }
+
+ void SetTitleTipBackClr(COLORREF clr = CLR_DEFAULT) { m_crTTipBackClr = clr; }
+ COLORREF GetTitleTipBackClr() { return m_crTTipBackClr; }
+ void SetTitleTipTextClr(COLORREF clr = CLR_DEFAULT) { m_crTTipTextClr = clr; }
+ COLORREF GetTitleTipTextClr() { return m_crTTipTextClr; }
+
+ // ***************************************************************************** //
+ // These have been deprecated. Use GetDefaultCell and then set the colors
+ void SetTextColor(COLORREF clr) { m_cellDefault.SetTextClr(clr); }
+ COLORREF GetTextColor() { return m_cellDefault.GetTextClr(); }
+ void SetTextBkColor(COLORREF clr) { m_cellDefault.SetBackClr(clr); }
+ COLORREF GetTextBkColor() { return m_cellDefault.GetBackClr(); }
+ void SetFixedTextColor(COLORREF clr) { m_cellFixedRowDef.SetTextClr(clr);
+ m_cellFixedColDef.SetTextClr(clr);
+ m_cellFixedRowColDef.SetTextClr(clr); }
+ COLORREF GetFixedTextColor() const { return m_cellFixedRowDef.GetTextClr(); }
+ void SetFixedBkColor(COLORREF clr) { m_cellFixedRowDef.SetBackClr(clr);
+ m_cellFixedColDef.SetBackClr(clr);
+ m_cellFixedRowColDef.SetBackClr(clr); }
+ COLORREF GetFixedBkColor() const { return m_cellFixedRowDef.GetBackClr(); }
+ void SetGridColor(COLORREF clr) { SetGridLineColor(clr); }
+ COLORREF GetGridColor() { return GetGridLineColor(); }
+ void SetBkColor(COLORREF clr) { SetGridBkColor(clr); }
+ COLORREF GetBkColor() { return GetGridBkColor(); }
+
+ void SetDefCellMargin( int nMargin) { m_cellDefault.SetMargin(nMargin);
+ m_cellFixedRowDef.SetMargin(nMargin);
+ m_cellFixedColDef.SetMargin(nMargin);
+ m_cellFixedRowColDef.SetMargin(nMargin); }
+ int GetDefCellMargin() const { return m_cellDefault.GetMargin(); }
+
+ int GetDefCellHeight() const { return m_cellDefault.GetHeight(); }
+ void SetDefCellHeight(int nHeight) { m_cellDefault.SetHeight(nHeight);
+ m_cellFixedRowDef.SetHeight(nHeight);
+ m_cellFixedColDef.SetHeight(nHeight);
+ m_cellFixedRowColDef.SetHeight(nHeight); }
+ int GetDefCellWidth() const { return m_cellDefault.GetWidth(); }
+ void SetDefCellWidth(int nWidth) { m_cellDefault.SetWidth(nWidth);
+ m_cellFixedRowDef.SetWidth(nWidth);
+ m_cellFixedColDef.SetWidth(nWidth);
+ m_cellFixedRowColDef.SetWidth(nWidth); }
+
+ // ***************************************************************************** //
+
+ int GetSelectedCount() const { return (int)m_SelectedCellMap.GetCount(); }
+
+ CCellID SetFocusCell(CCellID cell);
+ CCellID SetFocusCell(int nRow, int nCol);
+ CCellID GetFocusCell() const { return m_idCurrentCell; }
+
+
+ void SetVirtualMode(BOOL bVirtual);
+ BOOL GetVirtualMode() const { return m_bVirtualMode; }
+ void SetCallbackFunc(GRIDCALLBACK pCallback,
+ LPARAM lParam) { m_pfnCallback = pCallback; m_lParam = lParam; }
+ GRIDCALLBACK GetCallbackFunc() { return m_pfnCallback; }
+
+
+ void SetImageList(CImageList* pList) { m_pImageList = pList; }
+ CImageList* GetImageList() const { return m_pImageList; }
+
+ void SetGridLines(int nWhichLines = GVL_BOTH);
+ int GetGridLines() const { return m_nGridLines; }
+ void SetEditable(BOOL bEditable = TRUE) { m_bEditable = bEditable; }
+ BOOL IsEditable() const { return m_bEditable; }
+ void SetListMode(BOOL bEnableListMode = TRUE);
+ BOOL GetListMode() const { return m_bListMode; }
+ void SetSingleRowSelection(BOOL bSing = TRUE) { m_bSingleRowSelection = bSing; }
+ BOOL GetSingleRowSelection() { return m_bSingleRowSelection & m_bListMode; }
+ void SetSingleColSelection(BOOL bSing = TRUE) { m_bSingleColSelection = bSing; }
+ BOOL GetSingleColSelection() { return m_bSingleColSelection; }
+ void EnableSelection(BOOL bEnable = TRUE) { ResetSelectedRange(); m_bEnableSelection = bEnable; ResetSelectedRange(); }
+ BOOL IsSelectable() const { return m_bEnableSelection; }
+ void SetFixedColumnSelection(BOOL bSelect) { m_bFixedColumnSelection = bSelect;}
+ BOOL GetFixedColumnSelection() { return m_bFixedColumnSelection; }
+ void SetFixedRowSelection(BOOL bSelect) { m_bFixedRowSelection = bSelect; }
+ BOOL GetFixedRowSelection() { return m_bFixedRowSelection; }
+ void EnableDragAndDrop(BOOL bAllow = TRUE) { m_bAllowDragAndDrop = bAllow; }
+ BOOL GetDragAndDrop() const { return m_bAllowDragAndDrop; }
+ void SetRowResize(BOOL bResize = TRUE) { m_bAllowRowResize = bResize; }
+ BOOL GetRowResize() const { return m_bAllowRowResize; }
+ void SetColumnResize(BOOL bResize = TRUE) { m_bAllowColumnResize = bResize; }
+ BOOL GetColumnResize() const { return m_bAllowColumnResize; }
+ void SetHeaderSort(BOOL bSortOnClick = TRUE) { m_bSortOnClick = bSortOnClick; }
+ BOOL GetHeaderSort() const { return m_bSortOnClick; }
+ void SetHandleTabKey(BOOL bHandleTab = TRUE) { m_bHandleTabKey = bHandleTab; }
+ BOOL GetHandleTabKey() const { return m_bHandleTabKey; }
+ void SetDoubleBuffering(BOOL bBuffer = TRUE) { m_bDoubleBuffer = bBuffer; }
+ BOOL GetDoubleBuffering() const { return m_bDoubleBuffer; }
+ void EnableTitleTips(BOOL bEnable = TRUE) { m_bTitleTips = bEnable; }
+ BOOL GetTitleTips() { return m_bTitleTips; }
+ void SetSortColumn(int nCol);
+ int GetSortColumn() const { return m_nSortColumn; }
+ void SetSortAscending(BOOL bAscending) { m_bAscending = bAscending; }
+ BOOL GetSortAscending() const { return m_bAscending; }
+ void SetTrackFocusCell(BOOL bTrack) { m_bTrackFocusCell = bTrack; }
+ BOOL GetTrackFocusCell() { return m_bTrackFocusCell; }
+ void SetFrameFocusCell(BOOL bFrame) { m_bFrameFocus = bFrame; }
+ BOOL GetFrameFocusCell() { return m_bFrameFocus; }
+ void SetAutoSizeStyle(int nStyle = GVS_BOTH) { m_nAutoSizeColumnStyle = nStyle; }
+ int GetAutoSizeStyle() { return m_nAutoSizeColumnStyle; }
+
+ void EnableHiddenColUnhide(BOOL bEnable = TRUE){ m_bHiddenColUnhide = bEnable; }
+ BOOL GetHiddenColUnhide() { return m_bHiddenColUnhide; }
+ void EnableHiddenRowUnhide(BOOL bEnable = TRUE){ m_bHiddenRowUnhide = bEnable; }
+ BOOL GetHiddenRowUnhide() { return m_bHiddenRowUnhide; }
+
+ void EnableColumnHide(BOOL bEnable = TRUE) { m_bAllowColHide = bEnable; }
+ BOOL GetColumnHide() { return m_bAllowColHide; }
+ void EnableRowHide(BOOL bEnable = TRUE) { m_bAllowRowHide = bEnable; }
+ BOOL GetRowHide() { return m_bAllowRowHide; }
+
+///////////////////////////////////////////////////////////////////////////////////
+// default Grid cells. Use these for setting default values such as colors and fonts
+///////////////////////////////////////////////////////////////////////////////////
+public:
+ CGridCellBase* GetDefaultCell(BOOL bFixedRow, BOOL bFixedCol) const;
+
+///////////////////////////////////////////////////////////////////////////////////
+// Grid cell Attributes
+///////////////////////////////////////////////////////////////////////////////////
+public:
+ CGridCellBase* GetCell(int nRow, int nCol) const; // Get the actual cell!
+
+ void SetModified(BOOL bModified = TRUE, int nRow = -1, int nCol = -1);
+ BOOL GetModified(int nRow = -1, int nCol = -1);
+ BOOL IsCellFixed(int nRow, int nCol);
+
+ BOOL SetItem(const GV_ITEM* pItem);
+ BOOL GetItem(GV_ITEM* pItem);
+ BOOL SetItemText(int nRow, int nCol, LPCTSTR str);
+ // The following was virtual. If you want to override, use
+ // CGridCellBase-derived class's GetText() to accomplish same thing
+ CString GetItemText(int nRow, int nCol) const;
+
+ // EFW - 06/13/99 - Added to support printf-style formatting codes.
+ // Also supports use with a string resource ID
+#if !defined(_WIN32_WCE) || (_WIN32_WCE >= 210)
+ BOOL SetItemTextFmt(int nRow, int nCol, LPCTSTR szFmt, ...);
+ BOOL SetItemTextFmtID(int nRow, int nCol, UINT nID, ...);
+#endif
+
+ BOOL SetItemData(int nRow, int nCol, LPARAM lParam);
+ LPARAM GetItemData(int nRow, int nCol) const;
+ BOOL SetItemImage(int nRow, int nCol, int iImage);
+ int GetItemImage(int nRow, int nCol) const;
+ BOOL SetItemState(int nRow, int nCol, UINT state);
+ UINT GetItemState(int nRow, int nCol) const;
+ BOOL SetItemFormat(int nRow, int nCol, UINT nFormat);
+ UINT GetItemFormat(int nRow, int nCol) const;
+ BOOL SetItemBkColour(int nRow, int nCol, COLORREF cr = CLR_DEFAULT);
+ COLORREF GetItemBkColour(int nRow, int nCol) const;
+ BOOL SetItemFgColour(int nRow, int nCol, COLORREF cr = CLR_DEFAULT);
+ COLORREF GetItemFgColour(int nRow, int nCol) const;
+ BOOL SetItemFont(int nRow, int nCol, const LOGFONT* lf);
+ const LOGFONT* GetItemFont(int nRow, int nCol);
+
+ BOOL IsItemEditing(int nRow, int nCol);
+
+ BOOL SetCellType(int nRow, int nCol, CRuntimeClass* pRuntimeClass);
+ BOOL SetDefaultCellType( CRuntimeClass* pRuntimeClass);
+
+///////////////////////////////////////////////////////////////////////////////////
+// Operations
+///////////////////////////////////////////////////////////////////////////////////
+public:
+ int InsertColumn(LPCTSTR strHeading, UINT nFormat = DT_CENTER|DT_VCENTER|DT_SINGLELINE,
+ int nColumn = -1);
+ int InsertRow(LPCTSTR strHeading, int nRow = -1);
+ BOOL DeleteColumn(int nColumn);
+ BOOL DeleteRow(int nRow);
+ BOOL DeleteNonFixedRows();
+ BOOL DeleteAllItems();
+
+ void ClearCells(CCellRange Selection);
+
+ BOOL AutoSizeRow(int nRow, BOOL bResetScroll = TRUE);
+ BOOL AutoSizeColumn(int nCol, UINT nAutoSizeStyle = GVS_DEFAULT, BOOL bResetScroll = TRUE);
+ void AutoSizeRows();
+ void AutoSizeColumns(UINT nAutoSizeStyle = GVS_DEFAULT);
+ void AutoSize(UINT nAutoSizeStyle = GVS_DEFAULT);
+ void ExpandColumnsToFit(BOOL bExpandFixed = TRUE);
+ void ExpandLastColumn();
+ void ExpandRowsToFit(BOOL bExpandFixed = TRUE);
+ void ExpandToFit(BOOL bExpandFixed = TRUE);
+
+ void Refresh();
+ void AutoFill(); // Fill grid with blank cells
+
+ void EnsureVisible(CCellID &cell) { EnsureVisible(cell.row, cell.col); }
+ void EnsureVisible(int nRow, int nCol);
+ BOOL IsCellVisible(int nRow, int nCol);
+ BOOL IsCellVisible(CCellID cell);
+ BOOL IsCellEditable(int nRow, int nCol) const;
+ BOOL IsCellEditable(CCellID &cell) const;
+ BOOL IsCellSelected(int nRow, int nCol) const;
+ BOOL IsCellSelected(CCellID &cell) const;
+
+
+ // SetRedraw stops/starts redraws on things like changing the # rows/columns
+ // and autosizing, but not for user-intervention such as resizes
+ void SetRedraw(BOOL bAllowDraw, BOOL bResetScrollBars = FALSE);
+ BOOL RedrawCell(int nRow, int nCol, CDC* pDC = NULL);
+ BOOL RedrawCell(const CCellID& cell, CDC* pDC = NULL);
+ BOOL RedrawRow(int row);
+ BOOL RedrawColumn(int col);
+
+#ifndef _WIN32_WCE
+ BOOL Save(LPCTSTR filename, TCHAR chSeparator = _T(','));
+ BOOL Load(LPCTSTR filename, TCHAR chSeparator = _T(','));
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////
+// Cell Ranges
+///////////////////////////////////////////////////////////////////////////////////
+ public:
+ CCellRange GetCellRange() const;
+ CCellRange GetSelectedCellRange() const;
+ void SetSelectedRange(const CCellRange& Range, BOOL bForceRepaint = FALSE, BOOL bSelectCells = TRUE);
+ void SetSelectedRange(int nMinRow, int nMinCol, int nMaxRow, int nMaxCol,
+ BOOL bForceRepaint = FALSE, BOOL bSelectCells = TRUE);
+ BOOL IsValid(int nRow, int nCol) const;
+ BOOL IsValid(const CCellID& cell) const;
+ BOOL IsValid(const CCellRange& range) const;
+
+///////////////////////////////////////////////////////////////////////////////////
+// Clipboard, drag and drop, and cut n' paste operations
+///////////////////////////////////////////////////////////////////////////////////
+#ifndef GRIDCONTROL_NO_CLIPBOARD
+ virtual void CutSelectedText();
+ virtual COleDataSource* CopyTextFromGrid();
+ virtual BOOL PasteTextToGrid(CCellID cell, COleDataObject* pDataObject, BOOL bSelectPastedCells=TRUE);
+#endif
+
+#ifndef GRIDCONTROL_NO_DRAGDROP
+ public:
+ virtual void OnBeginDrag();
+ virtual DROPEFFECT OnDragEnter(COleDataObject* pDataObject, DWORD dwKeyState, CPoint point);
+ virtual DROPEFFECT OnDragOver(COleDataObject* pDataObject, DWORD dwKeyState, CPoint point);
+ virtual void OnDragLeave();
+ virtual BOOL OnDrop(COleDataObject* pDataObject, DROPEFFECT dropEffect, CPoint point);
+#endif
+
+#ifndef GRIDCONTROL_NO_CLIPBOARD
+ virtual void OnEditCut();
+ virtual void OnEditCopy();
+ virtual void OnEditPaste();
+#endif
+ virtual void OnEditSelectAll();
+
+///////////////////////////////////////////////////////////////////////////////////
+// Misc.
+///////////////////////////////////////////////////////////////////////////////////
+public:
+ CCellID GetNextItem(CCellID& cell, int nFlags) const;
+
+ BOOL SortItems(int nCol, BOOL bAscending, LPARAM data = 0);
+ BOOL SortTextItems(int nCol, BOOL bAscending, LPARAM data = 0);
+ BOOL SortItems(PFNLVCOMPARE pfnCompare, int nCol, BOOL bAscending, LPARAM data = 0);
+
+ void SetCompareFunction(PFNLVCOMPARE pfnCompare);
+
+ // in-built sort functions
+ static int CALLBACK pfnCellTextCompare(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort);
+ static int CALLBACK pfnCellNumericCompare(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort);
+
+///////////////////////////////////////////////////////////////////////////////////
+// Printing
+///////////////////////////////////////////////////////////////////////////////////
+#if !defined(_WIN32_WCE_NO_PRINTING) && !defined(GRIDCONTROL_NO_PRINTING)
+public:
+ void Print(CPrintDialog* pPrntDialog = NULL);
+
+ // EFW - New printing support functions
+ void EnableWysiwygPrinting(BOOL bEnable = TRUE) { m_bWysiwygPrinting = bEnable; }
+ BOOL GetWysiwygPrinting() { return m_bWysiwygPrinting; }
+
+ void SetShadedPrintOut(BOOL bEnable = TRUE) { m_bShadedPrintOut = bEnable; }
+ BOOL GetShadedPrintOut(void) { return m_bShadedPrintOut; }
+
+ // Use -1 to have it keep the existing value
+ void SetPrintMarginInfo(int nHeaderHeight, int nFooterHeight,
+ int nLeftMargin, int nRightMargin, int nTopMargin,
+ int nBottomMargin, int nGap);
+
+ void GetPrintMarginInfo(int &nHeaderHeight, int &nFooterHeight,
+ int &nLeftMargin, int &nRightMargin, int &nTopMargin,
+ int &nBottomMargin, int &nGap);
+
+///////////////////////////////////////////////////////////////////////////////////
+// Printing overrides for derived classes
+///////////////////////////////////////////////////////////////////////////////////
+public:
+ virtual void OnBeginPrinting(CDC *pDC, CPrintInfo *pInfo);
+ virtual void OnPrint(CDC *pDC, CPrintInfo *pInfo);
+ virtual void OnEndPrinting(CDC *pDC, CPrintInfo *pInfo);
+
+#endif // #if !defined(_WIN32_WCE_NO_PRINTING) && !defined(GRIDCONTROL_NO_PRINTING)
+
+// Implementation
+public:
+ virtual ~CGridCtrl();
+
+protected:
+ BOOL RegisterWindowClass();
+ BOOL Initialise();
+ void SetupDefaultCells();
+
+ LRESULT SendMessageToParent(int nRow, int nCol, int nMessage) const;
+ LRESULT SendDisplayRequestToParent(GV_DISPINFO* pDisplayInfo) const;
+ LRESULT SendCacheHintToParent(const CCellRange& range) const;
+
+ BOOL InvalidateCellRect(const int row, const int col);
+ BOOL InvalidateCellRect(const CCellID& cell);
+ BOOL InvalidateCellRect(const CCellRange& cellRange);
+ void EraseBkgnd(CDC* pDC);
+
+ BOOL GetCellRangeRect(const CCellRange& cellRange, LPRECT lpRect);
+
+ BOOL SetCell(int nRow, int nCol, CGridCellBase* pCell);
+
+ int SetMouseMode(int nMode) { int nOldMode = m_MouseMode; m_MouseMode = nMode; return nOldMode; }
+ int GetMouseMode() const { return m_MouseMode; }
+
+ BOOL MouseOverRowResizeArea(CPoint& point);
+ BOOL MouseOverColumnResizeArea(CPoint& point);
+
+ CCellID GetTopleftNonFixedCell(BOOL bForceRecalculation = FALSE);
+ CCellRange GetUnobstructedNonFixedCellRange(BOOL bForceRecalculation = FALSE);
+ // LUC
+ CCellRange GetVisibleNonFixedCellRange(LPRECT pRect = NULL, BOOL bForceRecalculation = FALSE);
+ CCellRange GetVisibleFixedCellRange(LPRECT pRect = NULL, BOOL bForceRecalculation = FALSE);
+
+ BOOL IsVisibleVScroll() { return ( (m_nBarState & GVL_VERT) > 0); }
+ BOOL IsVisibleHScroll() { return ( (m_nBarState & GVL_HORZ) > 0); }
+ void ResetSelectedRange();
+ void ResetScrollBars();
+ void EnableScrollBars(int nBar, BOOL bEnable = TRUE);
+ int GetScrollPos32(int nBar, BOOL bGetTrackPos = FALSE);
+ BOOL SetScrollPos32(int nBar, int nPos, BOOL bRedraw = TRUE);
+
+ BOOL SortTextItems(int nCol, BOOL bAscending, int low, int high);
+ BOOL SortItems(PFNLVCOMPARE pfnCompare, int nCol, BOOL bAscending, LPARAM data,
+ int low, int high);
+
+ CPoint GetPointClicked(int nRow, int nCol, const CPoint& point);
+
+ void ValidateAndModifyCellContents(int nRow, int nCol, LPCTSTR strText);
+
+// Overrrides
+ // ClassWizard generated virtual function overrides
+ //{{AFX_VIRTUAL(CGridCtrl)
+ protected:
+ virtual void PreSubclassWindow();
+ //}}AFX_VIRTUAL
+
+protected:
+#if !defined(_WIN32_WCE_NO_PRINTING) && !defined(GRIDCONTROL_NO_PRINTING)
+ // Printing
+ virtual void PrintFixedRowCells(int nStartColumn, int nStopColumn, int& row, CRect& rect,
+ CDC *pDC, BOOL& bFirst);
+ virtual void PrintColumnHeadings(CDC *pDC, CPrintInfo *pInfo);
+ virtual void PrintHeader(CDC *pDC, CPrintInfo *pInfo);
+ virtual void PrintFooter(CDC *pDC, CPrintInfo *pInfo);
+ virtual void PrintRowButtons(CDC *pDC, CPrintInfo* /*pInfo*/);
+#endif
+
+#ifndef GRIDCONTROL_NO_DRAGDROP
+ // Drag n' drop
+ virtual CImageList* CreateDragImage(CPoint *pHotSpot); // no longer necessary
+#endif
+
+ // Mouse Clicks
+ virtual void OnFixedColumnClick(CCellID& cell);
+ virtual void OnFixedRowClick(CCellID& cell);
+
+ // Editing
+ virtual void OnEditCell(int nRow, int nCol, CPoint point, UINT nChar);
+ virtual void OnEndEditCell(int nRow, int nCol, CString str);
+ virtual BOOL ValidateEdit(int nRow, int nCol, LPCTSTR str);
+ virtual void EndEditing();
+
+ // Drawing
+ virtual void OnDraw(CDC* pDC);
+
+ // CGridCellBase Creation and Cleanup
+ virtual CGridCellBase* CreateCell(int nRow, int nCol);
+ virtual void DestroyCell(int nRow, int nCol);
+
+// Attributes
+protected:
+ // General attributes
+ COLORREF m_crFixedTextColour, m_crFixedBkColour;
+ COLORREF m_crGridBkColour, m_crGridLineColour;
+ COLORREF m_crWindowText, m_crWindowColour, m_cr3DFace, // System colours
+ m_crShadow;
+ COLORREF m_crTTipBackClr, m_crTTipTextClr; // Titletip colours - FNA
+
+ BOOL m_bVirtualMode;
+ LPARAM m_lParam; // lParam for callback
+ GRIDCALLBACK m_pfnCallback; // The callback function
+
+ int m_nGridLines;
+ BOOL m_bEditable;
+ BOOL m_bModified;
+ BOOL m_bAllowDragAndDrop;
+ BOOL m_bListMode;
+ BOOL m_bSingleRowSelection;
+ BOOL m_bSingleColSelection;
+ BOOL m_bAllowDraw;
+ BOOL m_bEnableSelection;
+ BOOL m_bFixedRowSelection, m_bFixedColumnSelection;
+ BOOL m_bSortOnClick;
+ BOOL m_bHandleTabKey;
+ BOOL m_bDoubleBuffer;
+ BOOL m_bTitleTips;
+ int m_nBarState;
+ BOOL m_bWysiwygPrinting;
+ BOOL m_bHiddenColUnhide, m_bHiddenRowUnhide;
+ BOOL m_bAllowColHide, m_bAllowRowHide;
+ BOOL m_bAutoSizeSkipColHdr;
+ BOOL m_bTrackFocusCell;
+ BOOL m_bFrameFocus;
+ UINT m_nAutoSizeColumnStyle;
+
+ // Cell enable
+ vector<vector<CELL_ENABLE>> m_pCellEnable;
+
+ // Cell size details
+ int m_nRows, m_nFixedRows, m_nCols, m_nFixedCols;
+ // LUC
+ int m_nFreezedRows, m_nFreezedCols;
+ BOOL m_bExcludeFreezedRowsFromSelection;
+ BOOL m_bExcludeFreezedColsFromSelection;
+
+ // LUC
+ CArray<CCellRange, CCellRange&> m_arMergedCells;
+ // LUC
+ BOOL m_bShowHorzNonGridArea;
+
+ CUIntArray m_arRowHeights, m_arColWidths;
+ int m_nVScrollMax, m_nHScrollMax;
+
+ // Fonts and images
+ CRuntimeClass* m_pRtcDefault; // determines kind of Grid Cell created by default
+ CGridDefaultCell m_cellDefault; // "default" cell. Contains default colours, font etc.
+ CGridDefaultCell m_cellFixedColDef, m_cellFixedRowDef, m_cellFixedRowColDef;
+ CFont m_PrinterFont; // for the printer
+ CImageList* m_pImageList;
+
+ // Cell data
+ CTypedPtrArray<CObArray, GRID_ROW*> m_RowData;
+
+ // Mouse operations such as cell selection
+ int m_MouseMode;
+ BOOL m_bLMouseButtonDown, m_bRMouseButtonDown;
+ CPoint m_LeftClickDownPoint, m_LastMousePoint;
+ CCellID m_LeftClickDownCell, m_SelectionStartCell;
+ CCellID m_idCurrentCell, m_idTopLeftCell;
+ INT_PTR m_nTimerID;
+ int m_nTimerInterval;
+ int m_nResizeCaptureRange;
+ BOOL m_bAllowRowResize, m_bAllowColumnResize;
+ int m_nRowsPerWheelNotch;
+ CMap<DWORD,DWORD, CCellID, CCellID&> m_SelectedCellMap, m_PrevSelectedCellMap;
+
+#ifndef GRIDCONTROL_NO_TITLETIPS
+ CTitleTip m_TitleTip; // Title tips for cells
+#endif
+
+ // Drag and drop
+ CCellID m_LastDragOverCell;
+#ifndef GRIDCONTROL_NO_DRAGDROP
+ CGridDropTarget m_DropTarget; // OLE Drop target for the grid
+#endif
+
+ // Printing information
+ CSize m_CharSize;
+ int m_nPageHeight;
+ CSize m_LogicalPageSize, // Page size in gridctrl units.
+ m_PaperSize; // Page size in device units.
+ // additional properties to support Wysiwyg printing
+ int m_nPageWidth;
+ int m_nPrintColumn;
+ int m_nCurrPrintRow;
+ int m_nNumPages;
+ int m_nPageMultiplier;
+
+ // sorting
+ int m_bAscending;
+ int m_nSortColumn;
+ PFNLVCOMPARE m_pfnCompare;
+
+ // EFW - Added to support shaded/unshaded printout. If true, colored
+ // cells will print as-is. If false, all text prints as black on white.
+ BOOL m_bShadedPrintOut;
+
+ // EFW - Added support for user-definable margins. Top and bottom are in
+ // lines. Left, right, and gap are in characters (avg width is used).
+ int m_nHeaderHeight, m_nFooterHeight, m_nLeftMargin,
+ m_nRightMargin, m_nTopMargin, m_nBottomMargin, m_nGap;
+
+protected:
+ void SelectAllCells();
+ void SelectColumns(CCellID currentCell, BOOL bForceRedraw=FALSE, BOOL bSelectCells=TRUE);
+ void SelectRows(CCellID currentCell, BOOL bForceRedraw=FALSE, BOOL bSelectCells=TRUE);
+ void SelectCells(CCellID currentCell, BOOL bForceRedraw=FALSE, BOOL bSelectCells=TRUE);
+ void OnSelecting(const CCellID& currentCell);
+
+ // Generated message map functions
+ //{{AFX_MSG(CGridCtrl)
+ afx_msg void OnPaint();
+ afx_msg void OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar);
+ afx_msg void OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar);
+ afx_msg void OnSize(UINT nType, int cx, int cy);
+ afx_msg void OnLButtonUp(UINT nFlags, CPoint point);
+ afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
+ afx_msg void OnMouseMove(UINT nFlags, CPoint point);
+ afx_msg void OnTimer(UINT_PTR nIDEvent);
+ afx_msg UINT OnGetDlgCode();
+ afx_msg void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags);
+ afx_msg void OnKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags);
+ afx_msg void OnChar(UINT nChar, UINT nRepCnt, UINT nFlags);
+ afx_msg void OnLButtonDblClk(UINT nFlags, CPoint point);
+ afx_msg BOOL OnEraseBkgnd(CDC* pDC);
+ afx_msg void OnSysKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags);
+ afx_msg void OnUpdateEditSelectAll(CCmdUI* pCmdUI);
+ //}}AFX_MSG
+#ifndef _WIN32_WCE_NO_CURSOR
+ afx_msg BOOL OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message);
+#endif
+#ifndef _WIN32_WCE
+ afx_msg void OnRButtonDown(UINT nFlags, CPoint point);
+ afx_msg void OnRButtonUp(UINT nFlags, CPoint point); // EFW - Added
+ afx_msg void OnSysColorChange();
+#endif
+#ifndef _WIN32_WCE_NO_CURSOR
+ afx_msg void OnCaptureChanged(CWnd *pWnd);
+#endif
+#ifndef GRIDCONTROL_NO_CLIPBOARD
+ afx_msg void OnUpdateEditCopy(CCmdUI* pCmdUI);
+ afx_msg void OnUpdateEditCut(CCmdUI* pCmdUI);
+ afx_msg void OnUpdateEditPaste(CCmdUI* pCmdUI);
+#endif
+#if (_MFC_VER >= 0x0421) || (_WIN32_WCE >= 210)
+ afx_msg void OnSettingChange(UINT uFlags, LPCTSTR lpszSection);
+#endif
+#if !defined(_WIN32_WCE) && (_MFC_VER >= 0x0421)
+ afx_msg BOOL OnMouseWheel(UINT nFlags, short zDelta, CPoint pt);
+#endif
+ afx_msg LRESULT OnSetFont(WPARAM hFont, LPARAM lParam);
+ afx_msg LRESULT OnGetFont(WPARAM hFont, LPARAM lParam);
+ afx_msg LRESULT OnImeChar(WPARAM wCharCode, LPARAM lParam);
+ afx_msg void OnEndInPlaceEdit(NMHDR* pNMHDR, LRESULT* pResult);
+ afx_msg void OnComboSelChange(NMHDR* pNMHDR, LRESULT* pResult);
+ DECLARE_MESSAGE_MAP()
+
+ enum eMouseModes { MOUSE_NOTHING, MOUSE_SELECT_ALL, MOUSE_SELECT_COL, MOUSE_SELECT_ROW,
+ MOUSE_SELECT_CELLS, MOUSE_SCROLLING_CELLS,
+ MOUSE_OVER_ROW_DIVIDE, MOUSE_SIZING_ROW,
+ MOUSE_OVER_COL_DIVIDE, MOUSE_SIZING_COL,
+ MOUSE_PREPARE_EDIT,
+#ifndef GRIDCONTROL_NO_DRAGDROP
+ MOUSE_PREPARE_DRAG, MOUSE_DRAGGING
+#endif
+ };
+// for sort in virtual mode, and column order, save and load layer
+public:
+ typedef std::vector<int> intlist;
+ void Reorder(int From, int To);
+ void SetVirtualCompare(PVIRTUALCOMPARE VirtualCompare) { m_pfnVirtualCompare = VirtualCompare;}
+ int m_CurCol;
+ void AllowReorderColumn(bool b=true) { m_AllowReorderColumn = b;}
+ void EnableDragRowMode(bool b=true) { m_bDragRowMode = b; if(b) EnableDragAndDrop(); } // to change row order
+ int GetLayer(int** pLayer); // gives back the number of ints of the area (do not forget to delete *pLayer)
+ void SetLayer(int* pLayer); // coming from a previous GetLayer (ignored if not same number of column, or the same revision number)
+ void ForceQuitFocusOnTab(bool b=true) { m_QuitFocusOnTab = b;} // use only if GetParent() is a CDialog
+ void AllowSelectRowInFixedCol(bool b=true) { m_AllowSelectRowInFixedCol = b;} //
+// allow acces?
+ intlist m_arRowOrder, m_arColOrder;
+ static CGridCtrl* m_This;
+protected:
+ virtual void AddSubVirtualRow(int Num, int Nb);
+ bool m_bDragRowMode;
+ int m_CurRow;
+private:
+ void ResetVirtualOrder();
+ PVIRTUALCOMPARE m_pfnVirtualCompare;
+ static bool NotVirtualCompare(int c1, int c2);
+ bool m_InDestructor;
+ bool m_AllowReorderColumn;
+ bool m_QuitFocusOnTab;
+ bool m_AllowSelectRowInFixedCol;
+
+};
+
+// Returns the default cell implementation for the given grid region
+inline CGridCellBase* CGridCtrl::GetDefaultCell(BOOL bFixedRow, BOOL bFixedCol) const
+{
+ if (bFixedRow && bFixedCol) return (CGridCellBase*) &m_cellFixedRowColDef;
+ if (bFixedRow) return (CGridCellBase*) &m_cellFixedRowDef;
+ if (bFixedCol) return (CGridCellBase*) &m_cellFixedColDef;
+ return (CGridCellBase*) &m_cellDefault;
+}
+
+inline CGridCellBase* CGridCtrl::GetCell(int nRow, int nCol) const
+{
+ if (nRow < 0 || nRow >= m_nRows || nCol < 0 || nCol >= m_nCols)
+ return NULL;
+
+ if (GetVirtualMode())
+ {
+ CGridCellBase* pCell = GetDefaultCell(nRow < m_nFixedRows, nCol < m_nFixedCols);
+ static GV_DISPINFO gvdi;
+ gvdi.item.row = nRow;
+ gvdi.item.col = nCol;
+ gvdi.item.mask = 0xFFFFFFFF;
+ gvdi.item.nState = 0;
+ gvdi.item.nFormat = pCell->GetFormat();
+ gvdi.item.iImage = pCell->GetImage();
+ gvdi.item.crBkClr = pCell->GetBackClr();
+ gvdi.item.crFgClr = pCell->GetTextClr();
+ gvdi.item.lParam = pCell->GetData();
+ memcpy(&gvdi.item.lfFont, pCell->GetFont(), sizeof(LOGFONT));
+ gvdi.item.nMargin = pCell->GetMargin();
+ gvdi.item.strText.Empty();
+
+ // Fix the state bits
+ if (IsCellSelected(nRow, nCol)) gvdi.item.nState |= GVIS_SELECTED;
+ if (nRow < GetFixedRowCount()) gvdi.item.nState |= (GVIS_FIXED | GVIS_FIXEDROW);
+ if (nCol < GetFixedColumnCount()) gvdi.item.nState |= (GVIS_FIXED | GVIS_FIXEDCOL);
+ if (GetFocusCell() == CCellID(nRow, nCol)) gvdi.item.nState |= GVIS_FOCUSED;
+ if(!m_InDestructor)
+ {
+ gvdi.item.row = m_arRowOrder[nRow];
+ gvdi.item.col = m_arColOrder[nCol];
+
+ if (m_pfnCallback)
+ m_pfnCallback(&gvdi, m_lParam);
+ else
+ SendDisplayRequestToParent(&gvdi);
+ gvdi.item.row = nRow;
+ gvdi.item.col = nCol;
+ }
+ static CGridCell cell;
+ cell.SetState(gvdi.item.nState);
+ cell.SetFormat(gvdi.item.nFormat);
+ cell.SetImage(gvdi.item.iImage);
+ cell.SetBackClr(gvdi.item.crBkClr);
+ cell.SetTextClr(gvdi.item.crFgClr);
+ cell.SetData(gvdi.item.lParam);
+ cell.SetFont(&(gvdi.item.lfFont));
+ cell.SetMargin(gvdi.item.nMargin);
+ cell.SetText(gvdi.item.strText);
+ cell.SetGrid((CGridCtrl*)this);
+
+ return (CGridCellBase*) &cell;
+ }
+
+ GRID_ROW* pRow = m_RowData[nRow];
+ if (!pRow) return NULL;
+ if(pRow->GetData() == NULL)
+ return NULL;
+ return pRow->GetAt(m_arColOrder[nCol]);
+}
+
+inline BOOL CGridCtrl::SetCell(int nRow, int nCol, CGridCellBase* pCell)
+{
+ if (GetVirtualMode())
+ return FALSE;
+
+ if (nRow < 0 || nRow >= m_nRows || nCol < 0 || nCol >= m_nCols)
+ return FALSE;
+
+ GRID_ROW* pRow = m_RowData[nRow];
+ if (!pRow) return FALSE;
+
+ pCell->SetCoords( nRow, nCol);
+ pRow->SetAt(nCol, pCell);
+
+ return TRUE;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+//{{AFX_INSERT_LOCATION}}
+// Microsoft Developer Studio will insert additional declarations immediately before the previous line.
+
+#endif // !defined(AFX_GRIDCTRL_H__519FA702_722C_11D1_ABBA_00A0243D1382__INCLUDED_)
diff --git a/SourceCode/Bond/Servo/GridControl/GridDropTarget.cpp b/SourceCode/Bond/Servo/GridControl/GridDropTarget.cpp
new file mode 100644
index 0000000..c921abf
--- /dev/null
+++ b/SourceCode/Bond/Servo/GridControl/GridDropTarget.cpp
@@ -0,0 +1,156 @@
+// GridDropTarget.cpp : implementation file
+//
+// MFC Grid Control - Drag/Drop target implementation
+//
+// CGridDropTarget is an OLE drop target for CGridCtrl. All it does
+// is handle the drag and drop windows messages and pass them
+// directly onto the grid control.
+//
+// Written by Chris Maunder <chris@codeproject.com>
+// Copyright (c) 1998-2005. All Rights Reserved.
+//
+// This code may be used in compiled form in any way you desire. This
+// file may be redistributed unmodified by any means PROVIDING it is
+// not sold for profit without the authors written consent, and
+// providing that this notice and the authors name and all copyright
+// notices remains intact.
+//
+// An email letting me know how you are using it would be nice as well.
+//
+// This file is provided "as is" with no expressed or implied warranty.
+// The author accepts no liability for any damage/loss of business that
+// this product may cause.
+//
+// For use with CGridCtrl v2.10+
+//
+/////////////////////////////////////////////////////////////////////////////
+
+#include "stdafx.h"
+#include "GridCtrl.h"
+
+#ifndef GRIDCONTROL_NO_DRAGDROP
+#include "GridDropTarget.h"
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#undef THIS_FILE
+static const char* THIS_FILE = __FILE__;
+#endif
+
+/////////////////////////////////////////////////////////////////////////////
+// CGridDropTarget
+
+CGridDropTarget::CGridDropTarget()
+{
+ m_pGridCtrl = NULL;
+ m_bRegistered = FALSE;
+}
+
+CGridDropTarget::~CGridDropTarget()
+{
+}
+
+// Overloaded Register() function performs the normal COleDropTarget::Register
+// but also serves to connect this COleDropTarget with the parent grid control,
+// where all drop messages will ultimately be forwarded.
+BOOL CGridDropTarget::Register(CGridCtrl *pGridCtrl)
+{
+ if (m_bRegistered)
+ return FALSE;
+
+ // Stop re-entry problems
+ static BOOL bInProcedure = FALSE;
+ if (bInProcedure)
+ return FALSE;
+ bInProcedure = TRUE;
+
+// ASSERT(pGridCtrl->IsKindOf(RUNTIME_CLASS(CGridCtrl)));
+// ASSERT(pGridCtrl);
+
+ if (!pGridCtrl || !pGridCtrl->IsKindOf(RUNTIME_CLASS(CGridCtrl)))
+ {
+ bInProcedure = FALSE;
+ return FALSE;
+ }
+
+ m_pGridCtrl = pGridCtrl;
+
+ m_bRegistered = COleDropTarget::Register(pGridCtrl);
+
+ bInProcedure = FALSE;
+ return m_bRegistered;
+}
+
+void CGridDropTarget::Revoke()
+{
+ m_bRegistered = FALSE;
+ COleDropTarget::Revoke();
+}
+
+BEGIN_MESSAGE_MAP(CGridDropTarget, COleDropTarget)
+ //{{AFX_MSG_MAP(CGridDropTarget)
+ //}}AFX_MSG_MAP
+END_MESSAGE_MAP()
+
+/////////////////////////////////////////////////////////////////////////////
+// CGridDropTarget message handlers
+
+DROPEFFECT CGridDropTarget::OnDragScroll(CWnd* pWnd, DWORD dwKeyState, CPoint /*point*/)
+{
+// TRACE("In CGridDropTarget::OnDragScroll\n");
+ if (pWnd->GetSafeHwnd() == m_pGridCtrl->GetSafeHwnd())
+ {
+ if (dwKeyState & MK_CONTROL)
+ return DROPEFFECT_COPY;
+ else
+ return DROPEFFECT_MOVE;
+ } else
+ return DROPEFFECT_NONE;
+}
+
+DROPEFFECT CGridDropTarget::OnDragEnter(CWnd* pWnd, COleDataObject* pDataObject,
+ DWORD dwKeyState, CPoint point)
+{
+// TRACE(_T("In CGridDropTarget::OnDragEnter\n"));
+// ASSERT(m_pGridCtrl);
+
+ if (pWnd->GetSafeHwnd() == m_pGridCtrl->GetSafeHwnd())
+ return m_pGridCtrl->OnDragEnter(pDataObject, dwKeyState, point);
+ else
+ return DROPEFFECT_NONE;
+}
+
+void CGridDropTarget::OnDragLeave(CWnd* pWnd)
+{
+// TRACE(_T("In CGridDropTarget::OnDragLeave\n"));
+// ASSERT(m_pGridCtrl);
+
+ if (pWnd->GetSafeHwnd() == m_pGridCtrl->GetSafeHwnd())
+ m_pGridCtrl->OnDragLeave();
+}
+
+DROPEFFECT CGridDropTarget::OnDragOver(CWnd* pWnd, COleDataObject* pDataObject,
+ DWORD dwKeyState, CPoint point)
+{
+/// TRACE("In CGridDropTarget::OnDragOver\n");
+// ASSERT(m_pGridCtrl);
+
+ if (pWnd->GetSafeHwnd() == m_pGridCtrl->GetSafeHwnd())
+ return m_pGridCtrl->OnDragOver(pDataObject, dwKeyState, point);
+ else
+ return DROPEFFECT_NONE;
+}
+
+BOOL CGridDropTarget::OnDrop(CWnd* pWnd, COleDataObject* pDataObject,
+ DROPEFFECT dropEffect, CPoint point)
+{
+// TRACE(_T("In CGridDropTarget::OnDrop\n"));
+// ASSERT(m_pGridCtrl);
+
+ if (pWnd->GetSafeHwnd() == m_pGridCtrl->GetSafeHwnd())
+ return m_pGridCtrl->OnDrop(pDataObject, dropEffect, point);
+ else
+ return FALSE;
+}
+
+#endif // GRIDCONTROL_NO_DRAGDROP
\ No newline at end of file
diff --git a/SourceCode/Bond/Servo/GridControl/GridDropTarget.h b/SourceCode/Bond/Servo/GridControl/GridDropTarget.h
new file mode 100644
index 0000000..37788cf
--- /dev/null
+++ b/SourceCode/Bond/Servo/GridControl/GridDropTarget.h
@@ -0,0 +1,82 @@
+//////////////////////////////////////////////////////////////////////
+// GridDropTarget.h : header file
+//
+// MFC Grid Control - Drag/Drop target implementation
+//
+// Written by Chris Maunder <chris@codeproject.com>
+// Copyright (c) 1998-2005. All Rights Reserved.
+//
+// This code may be used in compiled form in any way you desire. This
+// file may be redistributed unmodified by any means PROVIDING it is
+// not sold for profit without the authors written consent, and
+// providing that this notice and the authors name and all copyright
+// notices remains intact.
+//
+// An email letting me know how you are using it would be nice as well.
+//
+// This file is provided "as is" with no expressed or implied warranty.
+// The author accepts no liability for any damage/loss of business that
+// this product may cause.
+//
+// For use with CGridCtrl v2.10+
+//
+//////////////////////////////////////////////////////////////////////
+
+#if !defined(AFX_GRIDDROPTARGET_H__5C610981_BD36_11D1_97CD_00A0243D1382__INCLUDED_)
+#define AFX_GRIDDROPTARGET_H__5C610981_BD36_11D1_97CD_00A0243D1382__INCLUDED_
+
+#if _MSC_VER >= 1000
+#pragma once
+#endif // _MSC_VER >= 1000
+
+
+#include <afxole.h>
+
+class CGridCtrl;
+
+/////////////////////////////////////////////////////////////////////////////
+// CGridDropTarget command target
+
+class CGridDropTarget : public COleDropTarget
+{
+public:
+ CGridDropTarget();
+ virtual ~CGridDropTarget();
+
+// Attributes
+public:
+ CGridCtrl* m_pGridCtrl;
+ BOOL m_bRegistered;
+
+// Operations
+public:
+ BOOL Register(CGridCtrl *pGridCtrl);
+ virtual void Revoke();
+
+ BOOL OnDrop(CWnd* pWnd, COleDataObject* pDataObject, DROPEFFECT dropEffect, CPoint point);
+ DROPEFFECT OnDragEnter(CWnd* pWnd, COleDataObject* pDataObject, DWORD dwKeyState, CPoint point);
+ void OnDragLeave(CWnd* pWnd);
+ DROPEFFECT OnDragOver(CWnd* pWnd, COleDataObject* pDataObject, DWORD dwKeyState, CPoint point);
+ DROPEFFECT OnDragScroll(CWnd* pWnd, DWORD dwKeyState, CPoint point);
+
+// Overrides
+ // ClassWizard generated virtual function overrides
+ //{{AFX_VIRTUAL(CGridDropTarget)
+ //}}AFX_VIRTUAL
+
+// Implementation
+protected:
+
+ // Generated message map functions
+ //{{AFX_MSG(CGridDropTarget)
+ //}}AFX_MSG
+
+ DECLARE_MESSAGE_MAP()
+};
+
+/////////////////////////////////////////////////////////////////////////////
+
+//{{AFX_INSERT_LOCATION}}
+// Microsoft Developer Studio will insert additional declarations immediately before the previous line.
+
+#endif // !defined(AFX_GRIDDROPTARGET_H__5C610981_BD36_11D1_97CD_00A0243D1382__INCLUDED_)
diff --git a/SourceCode/Bond/Servo/GridControl/GridInPlaceEdit.cpp b/SourceCode/Bond/Servo/GridControl/GridInPlaceEdit.cpp
new file mode 100644
index 0000000..9be4d81
--- /dev/null
+++ b/SourceCode/Bond/Servo/GridControl/GridInPlaceEdit.cpp
@@ -0,0 +1,262 @@
+// InPlaceEdit.cpp : implementation file
+//
+// Adapted by Chris Maunder <cmaunder@mail.com>
+// Copyright (c) 1998-2002. All Rights Reserved.
+//
+// The code contained in this file is based on the original
+// CGridInPlaceEdit from http://www.codeguru.com/listview/edit_subitems.shtml
+//
+// This code may be used in compiled form in any way you desire. This
+// file may be redistributed unmodified by any means PROVIDING it is
+// not sold for profit without the authors written consent, and
+// providing that this notice and the authors name and all copyright
+// notices remains intact.
+//
+// An email letting me know how you are using it would be nice as well.
+//
+// This file is provided "as is" with no expressed or implied warranty.
+// The author accepts no liability for any damage/loss of business that
+// this product may cause.
+//
+// For use with CGridCtrl v2.10+
+//
+// History:
+// 10 May 1998 Uses GVN_ notifications instead of LVN_,
+// Sends notification messages to the parent,
+// instead of the parent's parent.
+// 15 May 1998 There was a problem when editing with the in-place editor,
+// there arises a general protection fault in user.exe, with a
+// few qualifications:
+// (1) This only happens with owner-drawn buttons;
+// (2) This only happens in Win95
+// (3) This only happens if the handler for the button does not
+// create a new window (even an AfxMessageBox will avoid the
+// crash)
+// (4) This will not happen if Spy++ is running.
+// PreTranslateMessage was added to route messages correctly.
+// (Matt Weagle found and fixed this problem)
+// 26 Jul 1998 Removed the ES_MULTILINE style - that fixed a few probs!
+// 6 Aug 1998 Added nID to the constructor param list
+// 6 Sep 1998 Space no longer clears selection when starting edit (Franco Bez)
+// 10 Apr 1999 Enter, Tab and Esc key prob fixed (Koay Kah Hoe)
+// Workaround for bizzare "shrinking window" problem in CE
+//
+/////////////////////////////////////////////////////////////////////////////
+
+#include "stdafx.h"
+#include "TCHAR.h"
+#include "GridCtrl.h"
+#include "GridInPlaceEdit.h"
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#undef THIS_FILE
+static const char* THIS_FILE = __FILE__;
+#endif
+
+/////////////////////////////////////////////////////////////////////////////
+// CGridInPlaceEdit
+
+CGridInPlaceEdit::CGridInPlaceEdit(CWnd* pParent, CRect& rect, DWORD dwStyle, UINT nID,
+ int nRow, int nColumn, CString sInitText,
+ UINT nFirstChar)
+{
+ m_sInitText = sInitText;
+ m_nRow = nRow;
+ m_nColumn = nColumn;
+ m_nLastChar = 0;
+ m_bExitOnArrows = (nFirstChar != VK_LBUTTON); // If mouse click brought us here,
+ // then no exit on arrows
+
+ m_Rect = rect; // For bizarre CE bug.
+
+ DWORD dwEditStyle = WS_BORDER|WS_CHILD|WS_VISIBLE| ES_AUTOHSCROLL //|ES_MULTILINE
+ | dwStyle;
+ if (!Create(dwEditStyle, rect, pParent, nID)) return;
+
+ SetFont(pParent->GetFont());
+
+ SetWindowText(sInitText);
+ SetFocus();
+
+ switch (nFirstChar){
+ case VK_LBUTTON:
+ case VK_RETURN: SetSel((int)_tcslen(m_sInitText), -1); return;
+ case VK_BACK: SetSel((int)_tcslen(m_sInitText), -1); break;
+ case VK_TAB:
+ case VK_DOWN:
+ case VK_UP:
+ case VK_RIGHT:
+ case VK_LEFT:
+ case VK_NEXT:
+ case VK_PRIOR:
+ case VK_HOME:
+ case VK_SPACE:
+ case VK_END: SetSel(0,-1); return;
+ default: SetSel(0,-1);
+ }
+
+ // Added by KiteFly. When entering DBCS chars into cells the first char was being lost
+ // SenMessage changed to PostMessage (John Lagerquist)
+ if( nFirstChar < 0x80)
+ PostMessage(WM_CHAR, nFirstChar);
+ else
+ PostMessage(WM_IME_CHAR, nFirstChar);
+}
+
+CGridInPlaceEdit::~CGridInPlaceEdit()
+{
+}
+
+BEGIN_MESSAGE_MAP(CGridInPlaceEdit, CEdit)
+ //{{AFX_MSG_MAP(CGridInPlaceEdit)
+ ON_WM_KILLFOCUS()
+ ON_WM_CHAR()
+ ON_WM_KEYDOWN()
+ ON_WM_GETDLGCODE()
+ ON_WM_CREATE()
+ //}}AFX_MSG_MAP
+END_MESSAGE_MAP()
+
+////////////////////////////////////////////////////////////////////////////
+// CGridInPlaceEdit message handlers
+
+// If an arrow key (or associated) is pressed, then exit if
+// a) The Ctrl key was down, or
+// b) m_bExitOnArrows == TRUE
+void CGridInPlaceEdit::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
+{
+ if ((nChar == VK_PRIOR || nChar == VK_NEXT ||
+ nChar == VK_DOWN || nChar == VK_UP ||
+ nChar == VK_RIGHT || nChar == VK_LEFT) &&
+ (m_bExitOnArrows || GetKeyState(VK_CONTROL) < 0))
+ {
+ m_nLastChar = nChar;
+ GetParent()->SetFocus();
+ return;
+ }
+
+ CEdit::OnKeyDown(nChar, nRepCnt, nFlags);
+}
+
+// As soon as this edit loses focus, kill it.
+void CGridInPlaceEdit::OnKillFocus(CWnd* pNewWnd)
+{
+ CEdit::OnKillFocus(pNewWnd);
+ EndEdit();
+}
+
+void CGridInPlaceEdit::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)
+{
+ if (nChar == VK_TAB || nChar == VK_RETURN)
+ {
+ m_nLastChar = nChar;
+ GetParent()->SetFocus(); // This will destroy this window
+ return;
+ }
+ if (nChar == VK_ESCAPE)
+ {
+ SetWindowText(m_sInitText); // restore previous text
+ m_nLastChar = nChar;
+ GetParent()->SetFocus();
+ return;
+ }
+
+ CEdit::OnChar(nChar, nRepCnt, nFlags);
+
+ // Resize edit control if needed
+
+ // Get text extent
+ CString str;
+ GetWindowText( str );
+
+ // add some extra buffer
+ str += _T(" ");
+
+ CWindowDC dc(this);
+ CFont *pFontDC = dc.SelectObject(GetFont());
+ CSize size = dc.GetTextExtent( str );
+ dc.SelectObject( pFontDC );
+
+ // Get client rect
+ CRect ParentRect;
+ GetParent()->GetClientRect( &ParentRect );
+
+ // Check whether control needs to be resized
+ // and whether there is space to grow
+ if (size.cx > m_Rect.Width())
+ {
+ if( size.cx + m_Rect.left < ParentRect.right )
+ m_Rect.right = m_Rect.left + size.cx;
+ else
+ m_Rect.right = ParentRect.right;
+ MoveWindow( &m_Rect );
+ }
+}
+
+UINT CGridInPlaceEdit::OnGetDlgCode()
+{
+ return DLGC_WANTALLKEYS;
+}
+
+////////////////////////////////////////////////////////////////////////////
+// CGridInPlaceEdit overrides
+
+// Stoopid win95 accelerator key problem workaround - Matt Weagle.
+BOOL CGridInPlaceEdit::PreTranslateMessage(MSG* pMsg)
+{
+ // Catch the Alt key so we don't choke if focus is going to an owner drawn button
+ if (pMsg->message == WM_SYSCHAR)
+ return TRUE;
+
+ return CWnd::PreTranslateMessage(pMsg);
+}
+
+// Auto delete
+void CGridInPlaceEdit::PostNcDestroy()
+{
+ CEdit::PostNcDestroy();
+
+ delete this;
+}
+
+////////////////////////////////////////////////////////////////////////////
+// CGridInPlaceEdit implementation
+
+void CGridInPlaceEdit::EndEdit()
+{
+ CString str;
+
+ // EFW - BUG FIX - Clicking on a grid scroll bar in a derived class
+ // that validates input can cause this to get called multiple times
+ // causing assertions because the edit control goes away the first time.
+ static BOOL bAlreadyEnding = FALSE;
+
+ if(bAlreadyEnding)
+ return;
+
+ bAlreadyEnding = TRUE;
+ GetWindowText(str);
+
+ // Send Notification to parent
+ GV_DISPINFO dispinfo;
+
+ dispinfo.hdr.hwndFrom = GetSafeHwnd();
+ dispinfo.hdr.idFrom = GetDlgCtrlID();
+ dispinfo.hdr.code = GVN_ENDLABELEDIT;
+
+ dispinfo.item.mask = LVIF_TEXT|LVIF_PARAM;
+ dispinfo.item.row = m_nRow;
+ dispinfo.item.col = m_nColumn;
+ dispinfo.item.strText = str;
+ dispinfo.item.lParam = (LPARAM) m_nLastChar;
+
+ CWnd* pOwner = GetOwner();
+ if (pOwner)
+ pOwner->SendMessage(WM_NOTIFY, GetDlgCtrlID(), (LPARAM)&dispinfo );
+
+ // Close this window (PostNcDestroy will delete this)
+ if (IsWindow(GetSafeHwnd()))
+ SendMessage(WM_CLOSE, 0, 0);
+ bAlreadyEnding = FALSE;
+}
diff --git a/SourceCode/Bond/Servo/GridControl/GridInPlaceEdit.h b/SourceCode/Bond/Servo/GridControl/GridInPlaceEdit.h
new file mode 100644
index 0000000..b26b207
--- /dev/null
+++ b/SourceCode/Bond/Servo/GridControl/GridInPlaceEdit.h
@@ -0,0 +1,83 @@
+//////////////////////////////////////////////////////////////////////
+// InPlaceEdit.h : header file
+//
+// MFC Grid Control - inplace editing class
+//
+// Written by Chris Maunder <chris@codeproject.com>
+// Copyright (c) 1998-2005. All Rights Reserved.
+//
+// This code may be used in compiled form in any way you desire. This
+// file may be redistributed unmodified by any means PROVIDING it is
+// not sold for profit without the authors written consent, and
+// providing that this notice and the authors name and all copyright
+// notices remains intact.
+//
+// An email letting me know how you are using it would be nice as well.
+//
+// This file is provided "as is" with no expressed or implied warranty.
+// The author accepts no liability for any damage/loss of business that
+// this product may cause.
+//
+// For use with CGridCtrl v2.10+
+//
+//////////////////////////////////////////////////////////////////////
+
+#if !defined(AFX_INPLACEEDIT_H__ECD42821_16DF_11D1_992F_895E185F9C72__INCLUDED_)
+#define AFX_INPLACEEDIT_H__ECD42821_16DF_11D1_992F_895E185F9C72__INCLUDED_
+
+#if _MSC_VER >= 1000
+#pragma once
+#endif // _MSC_VER >= 1000
+
+class CGridInPlaceEdit : public CEdit
+{
+// Construction
+public:
+ CGridInPlaceEdit(CWnd* pParent, CRect& rect, DWORD dwStyle, UINT nID,
+ int nRow, int nColumn, CString sInitText, UINT nFirstChar);
+
+// Attributes
+public:
+
+// Operations
+public:
+ void EndEdit();
+
+// Overrides
+ // ClassWizard generated virtual function overrides
+ //{{AFX_VIRTUAL(CGridInPlaceEdit)
+ public:
+ virtual BOOL PreTranslateMessage(MSG* pMsg);
+ protected:
+ virtual void PostNcDestroy();
+ //}}AFX_VIRTUAL
+
+// Implementation
+public:
+ virtual ~CGridInPlaceEdit();
+
+// Generated message map functions
+protected:
+ //{{AFX_MSG(CGridInPlaceEdit)
+ afx_msg void OnKillFocus(CWnd* pNewWnd);
+ afx_msg void OnChar(UINT nChar, UINT nRepCnt, UINT nFlags);
+ afx_msg void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags);
+ afx_msg UINT OnGetDlgCode();
+ //}}AFX_MSG
+ DECLARE_MESSAGE_MAP()
+
+private:
+ int m_nRow;
+ int m_nColumn;
+ CString m_sInitText;
+ UINT m_nLastChar;
+ BOOL m_bExitOnArrows;
+ CRect m_Rect;
+};
+
+/////////////////////////////////////////////////////////////////////////////
+
+//{{AFX_INSERT_LOCATION}}
+// Microsoft Developer Studio will insert additional declarations immediately before the previous line.
+
+#endif // !defined(AFX_INPLACEEDIT_H__ECD42821_16DF_11D1_992F_895E185F9C72__INCLUDED_)
diff --git a/SourceCode/Bond/Servo/GridControl/GridMemDC.h b/SourceCode/Bond/Servo/GridControl/GridMemDC.h
new file mode 100644
index 0000000..f0f4894
--- /dev/null
+++ b/SourceCode/Bond/Servo/GridControl/GridMemDC.h
@@ -0,0 +1,106 @@
+#if !defined(AFX_MEMDC_H__CA1D3541_7235_11D1_ABBA_00A0243D1382__INCLUDED_)
+#define AFX_MEMDC_H__CA1D3541_7235_11D1_ABBA_00A0243D1382__INCLUDED_
+
+#if _MSC_VER >= 1000
+#pragma once
+#endif // _MSC_VER >= 1000
+// MemDC.h : header file
+//
+
+//////////////////////////////////////////////////
+// CGridMemDC - memory DC
+//
+// Author: Keith Rule
+// Email: keithr@europa.com
+// Copyright 1996-1997, Keith Rule
+//
+// You may freely use or modify this code provided this
+// Copyright is included in all derived versions.
+//
+// History - 10/3/97 Fixed scrolling bug.
+// Added print support.
+// 25 feb 98 - fixed minor assertion bug
+//
+// This class implements a memory Device Context
+
+class CGridMemDC : public CDC
+{
+public:
+
+ // constructor sets up the memory DC
+ CGridMemDC(CDC* pDC) : CDC()
+ {
+// ASSERT(pDC != NULL);
+
+ m_pDC = pDC;
+ m_pOldBitmap = NULL;
+#ifndef _WIN32_WCE_NO_PRINTING
+ m_bMemDC = !pDC->IsPrinting();
+#else
+ m_bMemDC = FALSE;
+#endif
+
+ if (m_bMemDC) // Create a Memory DC
+ {
+ pDC->GetClipBox(&m_rect);
+ CreateCompatibleDC(pDC);
+ m_bitmap.CreateCompatibleBitmap(pDC, m_rect.Width(), m_rect.Height());
+ m_pOldBitmap = SelectObject(&m_bitmap);
+#ifndef _WIN32_WCE
+ SetWindowOrg(m_rect.left, m_rect.top);
+#endif
+ // EFW - Bug fix - Fill background in case the user has overridden
+ // WM_ERASEBKGND. We end up with garbage otherwise.
+ // CJM - moved to fix a bug in the fix.
+ FillSolidRect(m_rect, pDC->GetBkColor());
+ }
+ else // Make a copy of the relevent parts of the current DC for printing
+ {
+#if !defined(_WIN32_WCE) || ((_WIN32_WCE > 201) && !defined(_WIN32_WCE_NO_PRINTING))
+ m_bPrinting = pDC->m_bPrinting;
+#endif
+ m_hDC = pDC->m_hDC;
+ m_hAttribDC = pDC->m_hAttribDC;
+ }
+
+ }
+
+ // Destructor copies the contents of the mem DC to the original DC
+ ~CGridMemDC()
+ {
+ if (m_bMemDC)
+ {
+ // Copy the offscreen bitmap onto the screen.
+ m_pDC->BitBlt(m_rect.left, m_rect.top, m_rect.Width(), m_rect.Height(),
+ this, m_rect.left, m_rect.top, SRCCOPY);
+
+ //Swap back the original bitmap.
+ SelectObject(m_pOldBitmap);
+ } else {
+ // All we need to do is replace the DC with an illegal value,
+ // this keeps us from accidently deleting the handles associated with
+ // the CDC that was passed to the constructor.
+ m_hDC = m_hAttribDC = NULL;
+ }
+ }
+
+ // Allow usage as a pointer
+ CGridMemDC* operator->() {return this;}
+
+ // Allow usage as a pointer
+ operator CGridMemDC*() {return this;}
+
+private:
+ CBitmap m_bitmap; // Offscreen bitmap
+ CBitmap* m_pOldBitmap; // bitmap originally found in CGridMemDC
+ CDC* m_pDC; // Saves CDC passed in constructor
+ CRect m_rect; // Rectangle of drawing area.
+ BOOL m_bMemDC; // TRUE if CDC really is a Memory DC.
+};
+
+/////////////////////////////////////////////////////////////////////////////
+
+//{{AFX_INSERT_LOCATION}}
+// Microsoft Developer Studio will insert additional declarations immediately before the previous line.
+
+#endif // !defined(AFX_MEMDC_H__CA1D3541_7235_11D1_ABBA_00A0243D1382__INCLUDED_)
diff --git a/SourceCode/Bond/Servo/GridControl/NewCellTypes/GridCellCheck.cpp b/SourceCode/Bond/Servo/GridControl/NewCellTypes/GridCellCheck.cpp
new file mode 100644
index 0000000..2db8970
--- /dev/null
+++ b/SourceCode/Bond/Servo/GridControl/NewCellTypes/GridCellCheck.cpp
@@ -0,0 +1,185 @@
+// GridCellCheck.cpp : implementation file
+//
+// MFC Grid Control - Main grid cell class
+//
+// Provides the implementation for a combobox cell type of the
+// grid control.
+//
+// Written by Chris Maunder <chris@codeproject.com>
+// Copyright (c) 1998-2005. All Rights Reserved.
+//
+// Parts of the code contained in this file are based on the original
+// CInPlaceList from http://www.codeguru.com/listview
+//
+// This code may be used in compiled form in any way you desire. This
+// file may be redistributed unmodified by any means PROVIDING it is
+// not sold for profit without the authors written consent, and
+// providing that this notice and the authors name and all copyright
+// notices remains intact.
+//
+// An email letting me know how you are using it would be nice as well.
+//
+// This file is provided "as is" with no expressed or implied warranty.
+// The author accepts no liability for any damage/loss of business that
+// this product may cause.
+//
+// For use with CGridCtrl v2.22+
+//
+// History:
+// 23 Jul 2001 - Complete rewrite
+// 13 Mar 2004 - GetCellExtent and GetCheckPlacement fixed by Yogurt
+// - Read-only now honoured - Yogurt
+//
+/////////////////////////////////////////////////////////////////////////////
+
+#include "stdafx.h"
+#include "GridCell.h"
+#include "GridCtrl.h"
+#include "GridCellCheck.h"
+
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#undef THIS_FILE
+static const char* THIS_FILE = __FILE__;
+#endif
+
+IMPLEMENT_DYNCREATE(CGridCellCheck, CGridCell)
+
+CGridCellCheck::CGridCellCheck() : CGridCell()
+{
+ m_bChecked = FALSE;
+ //m_Rect.IsRectNull();
+}
+
+CSize CGridCellCheck::GetCellExtent(CDC* pDC)
+{
+ // Using SM_CXHSCROLL as a guide to the size of the checkbox
+ int nWidth = GetSystemMetrics(SM_CXHSCROLL) + 2*GetMargin();
+ CSize cellSize = CGridCell::GetCellExtent(pDC);
+ cellSize.cx += nWidth;
+ cellSize.cy = max (cellSize.cy, nWidth);
+ return cellSize;
+}
+
+// i/o: i=dims of cell rect; o=dims of text rect
+BOOL CGridCellCheck::GetTextRect( LPRECT pRect)
+{
+ BOOL bResult = CGridCell::GetTextRect(pRect);
+ if (bResult)
+ {
+ int nWidth = GetSystemMetrics(SM_CXHSCROLL) + 2*GetMargin();
+ pRect->left += nWidth;
+ if (pRect->left > pRect->right)
+ pRect->left = pRect->right;
+ }
+ return bResult;
+}
+
+// Override draw so that when the cell is selected, a drop arrow is shown in the RHS.
+BOOL CGridCellCheck::Draw(CDC* pDC, int nRow, int nCol, CRect rect, BOOL bEraseBkgnd /*=TRUE*/)
+{
+ BOOL bResult = CGridCell::Draw(pDC, nRow, nCol, rect, bEraseBkgnd);
+
+#ifndef _WIN32_WCE
+ // Store the cell's dimensions for later
+ m_Rect = rect;
+
+ CRect CheckRect = GetCheckPlacement();
+ rect.left = CheckRect.right;
+
+ // enough room to draw?
+ // if (CheckRect.Width() < rect.Width() && CheckRect.Height() < rect.Height()) {
+
+ // Do the draw
+ pDC->DrawFrameControl(GetCheckPlacement(), DFC_BUTTON,
+ (m_bChecked)? DFCS_BUTTONCHECK | DFCS_CHECKED : DFCS_BUTTONCHECK);
+
+ // }
+#endif
+ return bResult;
+}
+
+void CGridCellCheck::OnClick(CPoint PointCellRelative)
+{
+ // PointCellRelative is relative to the topleft of the cell. Convert to client coords
+ PointCellRelative += m_Rect.TopLeft();
+
+ // Bail if cell is read-only
+ CCellID cell = GetGrid()->GetCellFromPt(PointCellRelative);
+ if (GetGrid()->isCellMaskActivated(cell.row, cell.col))
+ {
+ if (!GetGrid()->isCellMaskEditable(cell.row, cell.col))
+ {
+ return;
+ }
+ }
+ else
+ {
+ if (!GetGrid()->IsCellEditable(cell))
+ return;
+ }
+
+ // GetCheckPlacement returns the checkbox dimensions in client coords. Only check/
+ // uncheck if the user clicked in the box
+ if (GetCheckPlacement().PtInRect(PointCellRelative))
+ {
+ m_bChecked = !m_bChecked;
+ GetGrid()->InvalidateRect(m_Rect);
+ }
+}
+
+//////////////////////////////////////////////////////////////////////
+// Operations
+//////////////////////////////////////////////////////////////////////
+
+BOOL CGridCellCheck::SetCheck(BOOL bChecked /*=TRUE*/)
+{
+ BOOL bTemp = m_bChecked;
+ m_bChecked = bChecked;
+ if (!m_Rect.IsRectEmpty())
+ GetGrid()->InvalidateRect(m_Rect);
+
+ return bTemp;
+}
+
+BOOL CGridCellCheck::GetCheck()
+{
+ return m_bChecked;
+}
+
+//////////////////////////////////////////////////////////////////////
+// Protected implementation
+//////////////////////////////////////////////////////////////////////
+
+// Returns the dimensions and placement of the checkbox in client coords.
+CRect CGridCellCheck::GetCheckPlacement()
+{
+ int nWidth = GetSystemMetrics(SM_CXHSCROLL);
+ CRect place = m_Rect + CSize(GetMargin(), GetMargin());
+ place.right = place.left + nWidth;
+ place.bottom = place.top + nWidth;
+
+ /* for centering
+ int nDiff = (place.Width() - nWidth)/2;
+ if (nDiff > 0)
+ {
+ place.left += nDiff;
+ place.right = place.left + nWidth;
+ }
+ nDiff = (place.Height() - nWidth)/2;
+ if (nDiff > 0)
+ {
+ place.top += nDiff;
+ place.bottom = place.top + nWidth;
+ }
+ */
+
+ if (m_Rect.Height() < nWidth + 2 * static_cast<int> (GetMargin()))
+ {
+ place.top = m_Rect.top + (m_Rect.Height() - nWidth) / 2;
+ place.bottom = place.top + nWidth;
+ }
+
+ return place;
+}
\ No newline at end of file
diff --git a/SourceCode/Bond/Servo/GridControl/NewCellTypes/GridCellCheck.h b/SourceCode/Bond/Servo/GridControl/NewCellTypes/GridCellCheck.h
new file mode 100644
index 0000000..2a0981f
--- /dev/null
+++ b/SourceCode/Bond/Servo/GridControl/NewCellTypes/GridCellCheck.h
@@ -0,0 +1,68 @@
+#if !defined(AFX_GRIDCELLCHECK_H__ECD42822_16DF_11D1_992F_895E185F9C72__INCLUDED_)
+#define AFX_GRIDCELLCHECK_H__ECD42822_16DF_11D1_992F_895E185F9C72__INCLUDED_
+
+#if _MSC_VER >= 1000
+#pragma once
+#endif // _MSC_VER >= 1000
+
+/////////////////////////////////////////////////////////////////////////////
+// GridCellCheck.h : header file
+//
+// MFC Grid Control - Grid combo cell class header file
+//
+// Written by Chris Maunder <chris@codeproject.com>
+// Copyright (c) 1998-2005. All Rights Reserved.
+//
+// This code may be used in compiled form in any way you desire. This
+// file may be redistributed unmodified by any means PROVIDING it is
+// not sold for profit without the authors written consent, and
+// providing that this notice and the authors name and all copyright
+// notices remains intact.
+//
+// An email letting me know how you are using it would be nice as well.
+//
+// This file is provided "as is" with no expressed or implied warranty.
+// The author accepts no liability for any damage/loss of business that
+// this product may cause.
+//
+// For use with CGridCtrl v2.22+
+//
+//////////////////////////////////////////////////////////////////////
+
+
+#include "GridCell.h"
+
+
+class CGridCellCheck : public CGridCell
+{
+ friend class CGridCtrl;
+ DECLARE_DYNCREATE(CGridCellCheck)
+
+public:
+ CGridCellCheck();
+
+public:
+ BOOL SetCheck(BOOL bChecked = TRUE);
+ BOOL GetCheck();
+
+// Operations
+ virtual CSize GetCellExtent(CDC* pDC);
+ virtual void OnClick( CPoint PointCellRelative);
+ virtual BOOL GetTextRect( LPRECT pRect);
+
+protected:
+ CRect GetCheckPlacement();
+
+ virtual BOOL Draw(CDC* pDC, int nRow, int nCol, CRect rect, BOOL bEraseBkgnd = TRUE);
+
+protected:
+ BOOL m_bChecked;
+ CRect m_Rect;
+};
+
+/////////////////////////////////////////////////////////////////////////////
+
+//{{AFX_INSERT_LOCATION}}
+// Microsoft Developer Studio will insert additional declarations immediately before the previous line.
+
+#endif // !defined(AFX_GRIDCELLCHECK_H__ECD42822_16DF_11D1_992F_895E185F9C72__INCLUDED_)
diff --git a/SourceCode/Bond/Servo/GridControl/NewCellTypes/GridCellCombo.cpp b/SourceCode/Bond/Servo/GridControl/NewCellTypes/GridCellCombo.cpp
new file mode 100644
index 0000000..711b933
--- /dev/null
+++ b/SourceCode/Bond/Servo/GridControl/NewCellTypes/GridCellCombo.cpp
@@ -0,0 +1,510 @@
+// GridCellCombo.cpp : implementation file
+//
+// MFC Grid Control - Main grid cell class
+//
+// Provides the implementation for a combobox cell type of the
+// grid control.
+//
+// Written by Chris Maunder <chris@codeproject.com>
+// Copyright (c) 1998-2005. All Rights Reserved.
+//
+// Parts of the code contained in this file are based on the original
+// CInPlaceList from http://www.codeguru.com/listview
+//
+// This code may be used in compiled form in any way you desire. This
+// file may be redistributed unmodified by any means PROVIDING it is
+// not sold for profit without the authors written consent, and
+// providing that this notice and the authors name and all copyright
+// notices remains intact.
+//
+// An email letting me know how you are using it would be nice as well.
+//
+// This file is provided "as is" with no expressed or implied warranty.
+// The author accepts no liability for any damage/loss of business that
+// this product may cause.
+//
+// For use with CGridCtrl v2.22+
+//
+// History:
+// 6 Aug 1998 - Added CComboEdit to subclass the edit control - code
+// provided by Roelf Werkman <rdw@inn.nl>. Added nID to
+// the constructor param list.
+// 29 Nov 1998 - bug fix in onkeydown (Markus Irtenkauf)
+// 13 Mar 2004 - GetCellExtent fixed by Yogurt
+//
+/////////////////////////////////////////////////////////////////////////////
+
+#include "stdafx.h"
+#include "GridCell.h"
+#include "GridCtrl.h"
+#include "GridCellCombo.h"
+
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#undef THIS_FILE
+static const char* THIS_FILE = __FILE__;
+#endif
+
+
+/////////////////////////////////////////////////////////////////////////////
+// CComboEdit
+
+CComboEdit::CComboEdit()
+{
+}
+
+CComboEdit::~CComboEdit()
+{
+}
+
+// Stoopid win95 accelerator key problem workaround - Matt Weagle.
+BOOL CComboEdit::PreTranslateMessage(MSG* pMsg)
+{
+ // Make sure that the keystrokes continue to the appropriate handlers
+ if (pMsg->message == WM_KEYDOWN || pMsg->message == WM_KEYUP)
+ {
+ ::TranslateMessage(pMsg);
+ ::DispatchMessage(pMsg);
+ return TRUE;
+ }
+
+ // Catch the Alt key so we don't choke if focus is going to an owner drawn button
+ if (pMsg->message == WM_SYSCHAR)
+ return TRUE;
+
+ return CEdit::PreTranslateMessage(pMsg);
+}
+
+BEGIN_MESSAGE_MAP(CComboEdit, CEdit)
+ //{{AFX_MSG_MAP(CComboEdit)
+ ON_WM_KILLFOCUS()
+ ON_WM_KEYDOWN()
+ ON_WM_KEYUP()
+ //}}AFX_MSG_MAP
+END_MESSAGE_MAP()
+
+/////////////////////////////////////////////////////////////////////////////
+// CComboEdit message handlers
+
+void CComboEdit::OnKillFocus(CWnd* pNewWnd)
+{
+ CEdit::OnKillFocus(pNewWnd);
+
+ CInPlaceList* pOwner = (CInPlaceList*) GetOwner(); // This MUST be a CInPlaceList
+ if (pOwner)
+ pOwner->EndEdit();
+}
+
+void CComboEdit::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
+{
+ if ((nChar == VK_PRIOR || nChar == VK_NEXT ||
+ nChar == VK_DOWN || nChar == VK_UP ||
+ nChar == VK_RIGHT || nChar == VK_LEFT) &&
+ (GetKeyState(VK_CONTROL) < 0 && GetDlgCtrlID() == IDC_COMBOEDIT))
+ {
+ CWnd* pOwner = GetOwner();
+ if (pOwner)
+ pOwner->SendMessage(WM_KEYDOWN, nChar, nRepCnt+ (((DWORD)nFlags)<<16));
+ return;
+ }
+
+ CEdit::OnKeyDown(nChar, nRepCnt, nFlags);
+}
+
+void CComboEdit::OnKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags)
+{
+ if (nChar == VK_ESCAPE)
+ {
+ CWnd* pOwner = GetOwner();
+ if (pOwner)
+ pOwner->SendMessage(WM_KEYUP, nChar, nRepCnt + (((DWORD)nFlags)<<16));
+ return;
+ }
+
+ if (nChar == VK_TAB || nChar == VK_RETURN || nChar == VK_ESCAPE)
+ {
+ CWnd* pOwner = GetOwner();
+ if (pOwner)
+ pOwner->SendMessage(WM_KEYUP, nChar, nRepCnt + (((DWORD)nFlags)<<16));
+ return;
+ }
+
+ CEdit::OnKeyUp(nChar, nRepCnt, nFlags);
+}
+
+
+/////////////////////////////////////////////////////////////////////////////
+// CInPlaceList
+
+CInPlaceList::CInPlaceList(CWnd* pParent, CRect& rect, DWORD dwStyle, UINT nID,
+ int nRow, int nColumn,
+ COLORREF crFore, COLORREF crBack,
+ CStringArray& Items, CString sInitText,
+ UINT nFirstChar)
+{
+ m_crForeClr = crFore;
+ m_crBackClr = crBack;
+
+ m_nNumLines = 4;
+ m_sInitText = sInitText;
+ m_nRow = nRow;
+ m_nCol = nColumn;
+ m_nLastChar = 0;
+ m_bExitOnArrows = FALSE; //(nFirstChar != VK_LBUTTON); // If mouse click brought us here,
+
+ // Create the combobox
+ DWORD dwComboStyle = WS_BORDER|WS_CHILD|WS_VISIBLE|WS_VSCROLL|
+ CBS_AUTOHSCROLL | dwStyle;
+ int nHeight = rect.Height();
+ rect.bottom = rect.bottom + m_nNumLines*nHeight + ::GetSystemMetrics(SM_CYHSCROLL);
+ if (!Create(dwComboStyle, rect, pParent, nID)) return;
+
+ // Add the strings
+ for (int i = 0; i < Items.GetSize(); i++)
+ AddString(Items[i]);
+
+ SetFont(pParent->GetFont());
+ SetItemHeight(-1, nHeight);
+
+ int nMaxLength = GetCorrectDropWidth();
+ /*
+ if (nMaxLength > rect.Width())
+ rect.right = rect.left + nMaxLength;
+ // Resize the edit window and the drop down window
+ MoveWindow(rect);
+ */
+
+ SetDroppedWidth(nMaxLength);
+
+ SetHorizontalExtent(0); // no horz scrolling
+
+ // Set the initial text to m_sInitText
+ if (::IsWindow(m_hWnd) && SelectString(-1, m_sInitText) == CB_ERR)
+ SetWindowText(m_sInitText); // No text selected, so restore what was there before
+
+ ShowDropDown();
+
+ // Subclass the combobox edit control if style includes CBS_DROPDOWN
+ if ((dwStyle & CBS_DROPDOWNLIST) != CBS_DROPDOWNLIST)
+ {
+ m_edit.SubclassDlgItem(IDC_COMBOEDIT, this);
+ SetFocus();
+ switch (nFirstChar)
+ {
+ case VK_LBUTTON:
+ case VK_RETURN: m_edit.SetSel((int)_tcslen(m_sInitText), -1); return;
+ case VK_BACK: m_edit.SetSel((int)_tcslen(m_sInitText), -1); break;
+ case VK_DOWN:
+ case VK_UP:
+ case VK_RIGHT:
+ case VK_LEFT:
+ case VK_NEXT:
+ case VK_PRIOR:
+ case VK_HOME:
+ case VK_END: m_edit.SetSel(0,-1); return;
+ default: m_edit.SetSel(0,-1);
+ }
+ SendMessage(WM_CHAR, nFirstChar);
+ }
+ else
+ SetFocus();
+}
+
+CInPlaceList::~CInPlaceList()
+{
+}
+
+void CInPlaceList::EndEdit()
+{
+ CString str;
+ if (::IsWindow(m_hWnd))
+ GetWindowText(str);
+
+ // Send Notification to parent
+ GV_DISPINFO dispinfo;
+
+ dispinfo.hdr.hwndFrom = GetSafeHwnd();
+ dispinfo.hdr.idFrom = GetDlgCtrlID();
+ dispinfo.hdr.code = GVN_ENDLABELEDIT;
+
+ dispinfo.item.mask = LVIF_TEXT|LVIF_PARAM;
+ dispinfo.item.row = m_nRow;
+ dispinfo.item.col = m_nCol;
+ dispinfo.item.strText = str;
+ dispinfo.item.lParam = (LPARAM) m_nLastChar;
+
+ CWnd* pOwner = GetOwner();
+ if (IsWindow(pOwner->GetSafeHwnd()))
+ pOwner->SendMessage(WM_NOTIFY, GetDlgCtrlID(), (LPARAM)&dispinfo );
+
+ // Close this window (PostNcDestroy will delete this)
+ if (::IsWindow(m_hWnd))
+ PostMessage(WM_CLOSE, 0, 0);
+}
+
+int CInPlaceList::GetCorrectDropWidth()
+{
+ const int nMaxWidth = 200; // don't let the box be bigger than this
+
+ // Reset the dropped width
+ int nNumEntries = GetCount();
+ int nWidth = 0;
+ CString str;
+
+ CClientDC dc(this);
+ int nSave = dc.SaveDC();
+ dc.SelectObject(GetFont());
+
+ int nScrollWidth = ::GetSystemMetrics(SM_CXVSCROLL);
+ for (int i = 0; i < nNumEntries; i++)
+ {
+ GetLBText(i, str);
+ int nLength = dc.GetTextExtent(str).cx + nScrollWidth;
+ nWidth = max(nWidth, nLength);
+ }
+
+ // Add margin space to the calculations
+ nWidth += dc.GetTextExtent(_T("0")).cx;
+
+ dc.RestoreDC(nSave);
+
+ nWidth = min(nWidth, nMaxWidth);
+
+ return nWidth;
+ //SetDroppedWidth(nWidth);
+}
+
+/*
+// Fix by Ray (raybie@Exabyte.COM)
+void CInPlaceList::OnSelendOK()
+{
+ int iIndex = GetCurSel();
+ if( iIndex != CB_ERR)
+ {
+ CString strLbText;
+ GetLBText( iIndex, strLbText);
+
+ if (!((GetStyle() & CBS_DROPDOWNLIST) == CBS_DROPDOWNLIST))
+ m_edit.SetWindowText( strLbText);
+ }
+
+ GetParent()->SetFocus();
+}
+*/
+
+void CInPlaceList::PostNcDestroy()
+{
+ CComboBox::PostNcDestroy();
+
+ delete this;
+}
+
+BEGIN_MESSAGE_MAP(CInPlaceList, CComboBox)
+ //{{AFX_MSG_MAP(CInPlaceList)
+ ON_WM_KILLFOCUS()
+ ON_WM_KEYDOWN()
+ ON_WM_KEYUP()
+ ON_CONTROL_REFLECT(CBN_DROPDOWN, OnDropdown)
+ ON_CONTROL_REFLECT(CBN_SELCHANGE, OnSelChange)
+ ON_WM_GETDLGCODE()
+ ON_WM_CTLCOLOR_REFLECT()
+ //}}AFX_MSG_MAP
+ //ON_CONTROL_REFLECT(CBN_SELENDOK, OnSelendOK)
+END_MESSAGE_MAP()
+
+
+/////////////////////////////////////////////////////////////////////////////
+// CInPlaceList message handlers
+
+UINT CInPlaceList::OnGetDlgCode()
+{
+ return DLGC_WANTALLKEYS;
+}
+
+void CInPlaceList::OnDropdown()
+{
+ SetDroppedWidth(GetCorrectDropWidth());
+}
+
+void CInPlaceList::OnSelChange()
+{
+ CString str;
+ GetLBText(GetCurSel(), str);
+
+ // Send Notification to parent
+ GV_DISPINFO dispinfo;
+
+ dispinfo.hdr.hwndFrom = GetSafeHwnd();
+ dispinfo.hdr.idFrom = GetDlgCtrlID();
+ dispinfo.hdr.code = GVN_COMBOSELCHANGE;
+
+ dispinfo.item.mask = LVIF_TEXT|LVIF_PARAM;
+ dispinfo.item.row = m_nRow;
+ dispinfo.item.col = m_nCol;
+ dispinfo.item.strText = str;
+ dispinfo.item.lParam = (LPARAM) m_nLastChar;
+
+ CWnd* pOwner = GetOwner();
+ if (IsWindow(pOwner->GetSafeHwnd()))
+ pOwner->SendMessage(WM_NOTIFY, GetDlgCtrlID(), (LPARAM)&dispinfo);
+}
+
+void CInPlaceList::OnKillFocus(CWnd* pNewWnd)
+{
+ CComboBox::OnKillFocus(pNewWnd);
+
+ if (GetSafeHwnd() == pNewWnd->GetSafeHwnd())
+ return;
+
+ // Only end editing on change of focus if we're using the CBS_DROPDOWNLIST style
+ if ((GetStyle() & CBS_DROPDOWNLIST) == CBS_DROPDOWNLIST)
+ EndEdit();
+}
+
+// If an arrow key (or associated) is pressed, then exit if
+// a) The Ctrl key was down, or
+// b) m_bExitOnArrows == TRUE
+void CInPlaceList::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
+{
+ if ((nChar == VK_PRIOR || nChar == VK_NEXT ||
+ nChar == VK_DOWN || nChar == VK_UP ||
+ nChar == VK_RIGHT || nChar == VK_LEFT) &&
+ (m_bExitOnArrows || GetKeyState(VK_CONTROL) < 0))
+ {
+ m_nLastChar = nChar;
+ GetParent()->SetFocus();
+ return;
+ }
+
+ CComboBox::OnKeyDown(nChar, nRepCnt, nFlags);
+}
+
+// Need to keep a lookout for Tabs, Esc and Returns.
+void CInPlaceList::OnKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags)
+{
+ if (nChar == VK_ESCAPE)
+ SetWindowText(m_sInitText); // restore previous text
+
+ if (nChar == VK_TAB || nChar == VK_RETURN || nChar == VK_ESCAPE)
+ {
+ m_nLastChar = nChar;
+ GetParent()->SetFocus(); // This will destroy this window
+ return;
+ }
+
+ CComboBox::OnKeyUp(nChar, nRepCnt, nFlags);
+}
+
+HBRUSH CInPlaceList::CtlColor(CDC* /*pDC*/, UINT /*nCtlColor*/)
+{
+ /*
+ static CBrush brush(m_crBackClr);
+ pDC->SetTextColor(m_crForeClr);
+ pDC->SetBkMode(TRANSPARENT);
+ return (HBRUSH) brush.GetSafeHandle();
+ */
+
+ // TODO: Return a non-NULL brush if the parent's handler should not be called
+ return NULL;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// CGridCellCombo
+/////////////////////////////////////////////////////////////////////////////
+
+
+IMPLEMENT_DYNCREATE(CGridCellCombo, CGridCell)
+
+CGridCellCombo::CGridCellCombo() : CGridCell()
+{
+ SetStyle(CBS_DROPDOWN); // CBS_DROPDOWN, CBS_DROPDOWNLIST, CBS_SIMPLE, CBS_SORT
+}
+
+// Create a control to do the editing
+BOOL CGridCellCombo::Edit(int nRow, int nCol, CRect rect, CPoint /* point */, UINT nID, UINT nChar)
+{
+ m_bEditing = TRUE;
+
+ // CInPlaceList auto-deletes itself
+ m_pEditWnd = new CInPlaceList(GetGrid(), rect, GetStyle(), nID, nRow, nCol,
+ GetTextClr(), GetBackClr(), m_Strings, GetText(), nChar);
+
+ return TRUE;
+}
+
+CWnd* CGridCellCombo::GetEditWnd() const
+{
+ if (m_pEditWnd && (m_pEditWnd->GetStyle() & CBS_DROPDOWNLIST) != CBS_DROPDOWNLIST )
+ return &(((CInPlaceList*)m_pEditWnd)->m_edit);
+
+ return NULL;
+}
+
+
+CSize CGridCellCombo::GetCellExtent(CDC* pDC)
+{
+ CSize sizeScroll (GetSystemMetrics(SM_CXVSCROLL), GetSystemMetrics(SM_CYHSCROLL));
+ CSize sizeCell (CGridCell::GetCellExtent(pDC));
+ sizeCell.cx += sizeScroll.cx;
+ sizeCell.cy = max(sizeCell.cy,sizeScroll.cy);
+ return sizeCell;
+}
+
+// Cancel the editing.
+void CGridCellCombo::EndEdit()
+{
+ if (m_pEditWnd)
+ ((CInPlaceList*)m_pEditWnd)->EndEdit();
+}
+
+// Override draw so that when the cell is selected, a drop arrow is shown in the RHS.
+BOOL CGridCellCombo::Draw(CDC* pDC, int nRow, int nCol, CRect rect, BOOL bEraseBkgnd /*=TRUE*/)
+{
+#ifdef _WIN32_WCE
+ return CGridCell::Draw(pDC, nRow, nCol, rect, bEraseBkgnd);
+#else
+ // Cell selected?
+ //if ( !IsFixed() && IsFocused())
+ if (GetGrid()->IsCellEditable(nRow, nCol) && !IsEditing())
+ {
+ // Get the size of the scroll box
+ CSize sizeScroll(GetSystemMetrics(SM_CXVSCROLL), GetSystemMetrics(SM_CYHSCROLL));
+
+ // enough room to draw?
+ if (sizeScroll.cy < rect.Width() && sizeScroll.cy < rect.Height())
+ {
+ // Draw control at RHS of cell
+ CRect ScrollRect = rect;
+ ScrollRect.left = rect.right - sizeScroll.cx;
+ ScrollRect.bottom = rect.top + sizeScroll.cy;
+
+ // Do the draw
+ pDC->DrawFrameControl(ScrollRect, DFC_SCROLL, DFCS_SCROLLDOWN);
+
+ // Adjust the remaining space in the cell
+ rect.right = ScrollRect.left;
+ }
+ }
+
+ CString strTempText = GetText();
+ if (IsEditing())
+ SetText(_T(""));
+
+ // drop through and complete the cell drawing using the base class' method
+ BOOL bResult = CGridCell::Draw(pDC, nRow, nCol, rect, bEraseBkgnd);
+
+ if (IsEditing())
+ SetText(strTempText);
+
+ return bResult;
+#endif
+}
+
+// For setting the strings that will be displayed in the drop list
+void CGridCellCombo::SetOptions(const CStringArray& ar)
+{
+ m_Strings.RemoveAll();
+ for (int i = 0; i < ar.GetSize(); i++)
+ m_Strings.Add(ar[i]);
+}
\ No newline at end of file
diff --git a/SourceCode/Bond/Servo/GridControl/NewCellTypes/GridCellCombo.h b/SourceCode/Bond/Servo/GridControl/NewCellTypes/GridCellCombo.h
new file mode 100644
index 0000000..68fc54e
--- /dev/null
+++ b/SourceCode/Bond/Servo/GridControl/NewCellTypes/GridCellCombo.h
@@ -0,0 +1,178 @@
+#if !defined(AFX_GRIDCELLCOMBO_H__ECD42822_16DF_11D1_992F_895E185F9C72__INCLUDED_)
+#define AFX_GRIDCELLCOMBO_H__ECD42822_16DF_11D1_992F_895E185F9C72__INCLUDED_
+
+#if _MSC_VER >= 1000
+#pragma once
+#endif // _MSC_VER >= 1000
+
+/////////////////////////////////////////////////////////////////////////////
+// GridCellCombo.h : header file
+//
+// MFC Grid Control - Grid combo cell class header file
+//
+// Written by Chris Maunder <chris@codeproject.com>
+// Copyright (c) 1998-2005. All Rights Reserved.
+//
+// This code may be used in compiled form in any way you desire. This
+// file may be redistributed unmodified by any means PROVIDING it is
+// not sold for profit without the authors written consent, and
+// providing that this notice and the authors name and all copyright
+// notices remains intact.
+//
+// An email letting me know how you are using it would be nice as well.
+//
+// This file is provided "as is" with no expressed or implied warranty.
+// The author accepts no liability for any damage/loss of business that
+// this product may cause.
+//
+// For use with CGridCtrl v2.10
+//
+//////////////////////////////////////////////////////////////////////
+
+
+#include "GridCell.h"
+
+
+class CGridCellCombo : public CGridCell
+{
+ friend class CGridCtrl;
+ DECLARE_DYNCREATE(CGridCellCombo)
+
+public:
+ CGridCellCombo();
+
+// editing cells
+public:
+ virtual BOOL Edit(int nRow, int nCol, CRect rect, CPoint point, UINT nID, UINT nChar);
+ virtual CWnd* GetEditWnd() const;
+ virtual void EndEdit();
+
+// Operations
+public:
+ virtual CSize GetCellExtent(CDC* pDC);
+
+// CGridCellCombo specific calls
+public:
+ void SetOptions(const CStringArray& ar);
+ void SetStyle(DWORD dwStyle) { m_dwStyle = dwStyle; }
+ DWORD GetStyle() { return m_dwStyle; }
+
+protected:
+ virtual BOOL Draw(CDC* pDC, int nRow, int nCol, CRect rect, BOOL bEraseBkgnd = TRUE);
+
+ CStringArray m_Strings;
+ DWORD m_dwStyle;
+};
+
+
+
+/////////////////////////////////////////////////////////////////////////////
+// CComboEdit window
+
+#define IDC_COMBOEDIT 1001
+
+class CComboEdit : public CEdit
+{
+// Construction
+public:
+ CComboEdit();
+
+// Attributes
+public:
+
+// Operations
+public:
+
+// Overrides
+ // ClassWizard generated virtual function overrides
+ //{{AFX_VIRTUAL(CComboEdit)
+ virtual BOOL PreTranslateMessage(MSG* pMsg);
+ //}}AFX_VIRTUAL
+
+// Implementation
+public:
+ virtual ~CComboEdit();
+
+ // Generated message map functions
+protected:
+ //{{AFX_MSG(CComboEdit)
+ afx_msg void OnKillFocus(CWnd* pNewWnd);
+ afx_msg void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags);
+ afx_msg void OnKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags);
+ //}}AFX_MSG
+
+ DECLARE_MESSAGE_MAP()
+};
+
+/////////////////////////////////////////////////////////////////////////////
+// CInPlaceList window
+
+class CInPlaceList : public CComboBox
+{
+ friend class CComboEdit;
+
+// Construction
+public:
+ CInPlaceList(CWnd* pParent, // parent
+ CRect& rect, // dimensions & location
+ DWORD dwStyle, // window/combobox style
+ UINT nID, // control ID
+ int nRow, int nColumn, // row and column
+ COLORREF crFore, COLORREF crBack, // Foreground, background colour
+ CStringArray& Items, // Items in list
+ CString sInitText, // initial selection
+ UINT nFirstChar); // first character to pass to control
+
+// Attributes
+public:
+ CComboEdit m_edit; // subclassed edit control
+
+// Operations
+public:
+
+// Overrides
+ // ClassWizard generated virtual function overrides
+ //{{AFX_VIRTUAL(CInPlaceList)
+ protected:
+ virtual void PostNcDestroy();
+ //}}AFX_VIRTUAL
+
+// Implementation
+public:
+ virtual ~CInPlaceList();
+ void EndEdit();
+
+protected:
+ int GetCorrectDropWidth();
+
+// Generated message map functions
+protected:
+ //{{AFX_MSG(CInPlaceList)
+ afx_msg void OnKillFocus(CWnd* pNewWnd);
+ afx_msg void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags);
+ afx_msg void OnKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags);
+ afx_msg void OnDropdown();
+ afx_msg void OnSelChange();
+ afx_msg UINT OnGetDlgCode();
+ afx_msg HBRUSH CtlColor(CDC* pDC, UINT nCtlColor);
+ //}}AFX_MSG
+ //afx_msg void OnSelendOK();
+
+ DECLARE_MESSAGE_MAP()
+
+private:
+ int m_nNumLines;
+ CString m_sInitText;
+ int m_nRow;
+ int m_nCol;
+ UINT m_nLastChar;
+ BOOL m_bExitOnArrows;
+ COLORREF m_crForeClr, m_crBackClr;
+};
+
+/////////////////////////////////////////////////////////////////////////////
+
+//{{AFX_INSERT_LOCATION}}
+// Microsoft Developer Studio will insert additional declarations immediately before the previous line.
+
+#endif // !defined(AFX_GRIDCELLCOMBO_H__ECD42822_16DF_11D1_992F_895E185F9C72__INCLUDED_)
diff --git a/SourceCode/Bond/Servo/GridControl/NewCellTypes/GridCellDateTime.cpp b/SourceCode/Bond/Servo/GridControl/NewCellTypes/GridCellDateTime.cpp
new file mode 100644
index 0000000..f643042
--- /dev/null
+++ b/SourceCode/Bond/Servo/GridControl/NewCellTypes/GridCellDateTime.cpp
@@ -0,0 +1,268 @@
+///////////////////////////////////////////////////////////////////////////
+//
+// GridCellDateTime.cpp: implementation of the CGridCellDateTime class.
+//
+// Provides the implementation for a datetime picker cell type of the
+// grid control.
+//
+// Written by Podsypalnikov Eugen 15 Mar 2001
+// Modified:
+// 31 May 2001 Fixed m_cTime bug (Chris Maunder)
+//
+// For use with CGridCtrl v2.22+
+//
+///////////////////////////////////////////////////////////////////////////
+
+#include "stdafx.h"
+#include "GridCtrl.h"
+#include "GridCellDateTime.h"
+
+#ifdef _DEBUG
+#undef THIS_FILE
+static const char* THIS_FILE=__FILE__;
+#define new DEBUG_NEW
+#endif
+
+//////////////////////////////////////////////////////////////////////
+// CGridCellDateTime
+
+IMPLEMENT_DYNCREATE(CGridCellDateTime, CGridCell)
+
+//////////////////////////////////////////////////////////////////////
+// Construction/Destruction
+//////////////////////////////////////////////////////////////////////
+
+CGridCellDateTime::CGridCellDateTime() : CGridCell()
+{
+ m_dwStyle = 0;
+ m_cTime = CTime::GetCurrentTime();
+}
+
+CGridCellDateTime::CGridCellDateTime(DWORD dwStyle) : CGridCell()
+{
+ Init(dwStyle);
+}
+
+CGridCellDateTime::~CGridCellDateTime()
+{
+}
+
+CSize CGridCellDateTime::GetCellExtent(CDC* pDC)
+{
+ CSize sizeScroll (GetSystemMetrics(SM_CXVSCROLL), GetSystemMetrics(SM_CYHSCROLL));
+ CSize sizeCell (CGridCell::GetCellExtent(pDC));
+ sizeCell.cx += sizeScroll.cx;
+ sizeCell.cy = max(sizeCell.cy,sizeScroll.cy);
+ return sizeCell;
+}
+
+BOOL CGridCellDateTime::Edit(int nRow, int nCol, CRect rect, CPoint /* point */,
+ UINT nID, UINT nChar)
+{
+ m_bEditing = TRUE;
+
+ // CInPlaceDateTime auto-deletes itself
+ m_pEditWnd = new CInPlaceDateTime(GetGrid(), rect,
+ m_dwStyle|DTS_UPDOWN, nID, nRow, nCol,
+ GetTextClr(), GetBackClr(), GetTime(), nChar);
+ return TRUE;
+}
+
+CWnd* CGridCellDateTime::GetEditWnd() const
+{
+ return m_pEditWnd;
+}
+
+void CGridCellDateTime::EndEdit()
+{
+ if (m_pEditWnd) ((CInPlaceDateTime*)m_pEditWnd)->EndEdit();
+}
+
+void CGridCellDateTime::Init(DWORD dwStyle)
+{
+ m_dwStyle = dwStyle;
+
+ SetTime(CTime::GetCurrentTime());
+
+ SetFormat(DT_CENTER|DT_VCENTER|DT_SINGLELINE|DT_NOPREFIX
+#ifndef _WIN32_WCE
+ |DT_END_ELLIPSIS
+#endif
+ );
+}
+
+// Should be changed to use locale settings
+void CGridCellDateTime::SetTime(CTime time)
+{
+ m_cTime = time;
+
+ if (DTS_TIMEFORMAT == m_dwStyle)
+ {
+#ifdef _WIN32_WCE
+ CString strTemp;
+ strTemp.Format(_T("%02d:%02d:%02d"),
+ m_cTime.GetHour(), m_cTime.GetMinute(), m_cTime.GetSecond());
+ SetText(strTemp);
+#else
+
+// SetText(m_cTime.Format(_T("%H:%M:%S")));
+ SetText(m_cTime.Format(_T("%X")));
+#endif
+ }
+ else if (DTS_SHORTDATEFORMAT == m_dwStyle)
+ {
+#ifdef _WIN32_WCE
+ CString strTemp;
+ strTemp.Format(_T("%02d/%02d/%02d"),
+ m_cTime.GetMonth(), m_cTime.GetDay(), m_cTime.GetYear());
+ SetText(strTemp);
+#else
+// SetText(m_cTime.Format(("%d/%m/%Y")));
+ SetText(m_cTime.Format(("%x")));
+#endif
+ }
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// CInPlaceDateTime
+
+CInPlaceDateTime::CInPlaceDateTime(CWnd* pParent, CRect& rect, DWORD dwStyle, UINT nID,
+ int nRow, int nColumn,
+ COLORREF crFore, COLORREF crBack,
+ CTime* pcTime,
+ UINT nFirstChar)
+{
+ m_crForeClr = crFore;
+ m_crBackClr = crBack;
+ m_nRow = nRow;
+ m_nCol = nColumn;
+ m_nLastChar = 0;
+ m_bExitOnArrows = FALSE;
+ m_pcTime = pcTime;
+
+ DWORD dwStl = WS_BORDER|WS_VISIBLE|WS_CHILD|dwStyle;
+
+ if (!Create(dwStl, rect, pParent, nID)) {
+ return;
+ }
+
+ SetTime(m_pcTime);
+
+ SetFont(pParent->GetFont());
+ SetFocus();
+
+ switch (nFirstChar)
+ {
+ case VK_LBUTTON:
+ case VK_RETURN: return;
+ case VK_BACK: break;
+ case VK_DOWN:
+ case VK_UP:
+ case VK_RIGHT:
+ case VK_LEFT:
+ case VK_NEXT:
+ case VK_PRIOR:
+ case VK_HOME:
+ case VK_END: return;
+ default: break;
+ }
+ SendMessage(WM_CHAR, nFirstChar);
+}
+
+CInPlaceDateTime::~CInPlaceDateTime()
+{
+}
+
+void CInPlaceDateTime::EndEdit()
+{
+ CString str;
+ if (::IsWindow(m_hWnd))
+ {
+ GetWindowText(str);
+ GetTime(*m_pcTime);
+ }
+
+ // Send Notification to parent
+ GV_DISPINFO dispinfo;
+
+ dispinfo.hdr.hwndFrom = GetSafeHwnd();
+ dispinfo.hdr.idFrom = GetDlgCtrlID();
+ dispinfo.hdr.code = GVN_ENDLABELEDIT;
+
+ dispinfo.item.mask = LVIF_TEXT|LVIF_PARAM;
+ dispinfo.item.row = m_nRow;
+ dispinfo.item.col = m_nCol;
+ dispinfo.item.strText = str;
+ dispinfo.item.lParam = (LPARAM) m_nLastChar;
+
+ CWnd* pOwner = GetOwner();
+ if (IsWindow(pOwner->GetSafeHwnd())) {
+ pOwner->SendMessage(WM_NOTIFY, GetDlgCtrlID(), (LPARAM)&dispinfo);
+ }
+
+ // Close this window (PostNcDestroy will delete this)
+ if (::IsWindow(m_hWnd)) {
+ PostMessage(WM_CLOSE, 0, 0);
+ }
+}
+
+void CInPlaceDateTime::PostNcDestroy()
+{
+ CDateTimeCtrl::PostNcDestroy();
+ delete this;
+}
+
+BEGIN_MESSAGE_MAP(CInPlaceDateTime, CDateTimeCtrl)
+ //{{AFX_MSG_MAP(CInPlaceDateTime)
+ ON_WM_KILLFOCUS()
+ ON_WM_KEYDOWN()
+ ON_WM_KEYUP()
+ ON_WM_GETDLGCODE()
+ //}}AFX_MSG_MAP
+END_MESSAGE_MAP()
+
+
+/////////////////////////////////////////////////////////////////////////////
+// CInPlaceDateTime message handlers
+
+void CInPlaceDateTime::OnKillFocus(CWnd* pNewWnd)
+{
+ CDateTimeCtrl::OnKillFocus(pNewWnd);
+
+ if (GetSafeHwnd() == pNewWnd->GetSafeHwnd()) {
+ return;
+ }
+ EndEdit();
+}
+
+UINT CInPlaceDateTime::OnGetDlgCode()
+{
+ return DLGC_WANTALLKEYS;
+}
+
+void CInPlaceDateTime::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
+{
+ if (( nChar == VK_PRIOR || nChar == VK_NEXT ||
+ nChar == VK_DOWN || nChar == VK_UP ||
+ nChar == VK_RIGHT || nChar == VK_LEFT) &&
+ (m_bExitOnArrows || GetKeyState(VK_CONTROL) < 0))
+ {
+ m_nLastChar = nChar;
+ GetParent()->SetFocus();
+ return;
+ }
+
+ CDateTimeCtrl::OnKeyDown(nChar, nRepCnt, nFlags);
+}
+
+void CInPlaceDateTime::OnKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags)
+{
+ if (nChar == VK_TAB || nChar == VK_RETURN || nChar == VK_ESCAPE)
+ {
+ m_nLastChar = nChar;
+ GetParent()->SetFocus(); // This will destroy this window
+ return;
+ }
+
+ CDateTimeCtrl::OnKeyUp(nChar, nRepCnt, nFlags);
+}
diff --git a/SourceCode/Bond/Servo/GridControl/NewCellTypes/GridCellDateTime.h b/SourceCode/Bond/Servo/GridControl/NewCellTypes/GridCellDateTime.h
new file mode 100644
index 0000000..e7d9c1c
--- /dev/null
+++ b/SourceCode/Bond/Servo/GridControl/NewCellTypes/GridCellDateTime.h
@@ -0,0 +1,92 @@
+// GridCellDateTime.h: interface for the CGridCellDateTime class.
+//
+// Provides the implementation for a datetime picker cell type of the
+// grid control.
+//
+// For use with CGridCtrl v2.22+
+//
+//////////////////////////////////////////////////////////////////////
+
+#if !defined(AFX_DATETIMECELL_H__A0B7DA0A_0AFE_4D28_A00E_846C96D7507A__INCLUDED_)
+#define AFX_DATETIMECELL_H__A0B7DA0A_0AFE_4D28_A00E_846C96D7507A__INCLUDED_
+
+#if _MSC_VER > 1000
+#pragma once
+#endif // _MSC_VER > 1000
+
+#include "GridCell.h"
+#include "afxdtctl.h" // for CDateTimeCtrl
+
+class CGridCellDateTime : public CGridCell
+{
+ friend class CGridCtrl;
+ DECLARE_DYNCREATE(CGridCellDateTime)
+
+ CTime m_cTime;
+ DWORD m_dwStyle;
+
+public:
+ CGridCellDateTime();
+ CGridCellDateTime(DWORD dwStyle);
+ virtual ~CGridCellDateTime();
+ virtual CSize GetCellExtent(CDC* pDC);
+
+ // editing cells
+public:
+ void Init(DWORD dwStyle);
+ virtual BOOL Edit(int nRow, int nCol, CRect rect, CPoint point, UINT nID, UINT nChar);
+ virtual CWnd* GetEditWnd() const;
+ virtual void EndEdit();
+
+
+ CTime* GetTime() {return &m_cTime;};
+ void SetTime(CTime time);
+};
+
+class CInPlaceDateTime : public CDateTimeCtrl
+{
+// Construction
+public:
+ CInPlaceDateTime(CWnd* pParent, // parent
+ CRect& rect, // dimensions & location
+ DWORD dwStyle, // window/combobox style
+ UINT nID, // control ID
+ int nRow, int nColumn, // row and column
+ COLORREF crFore, COLORREF crBack, // Foreground, background colour
+ CTime* pcTime,
+ UINT nFirstChar); // first character to pass to control
+
+// Overrides
+ // ClassWizard generated virtual function overrides
+ //{{AFX_VIRTUAL(CInPlaceList)
+ protected:
+ virtual void PostNcDestroy();
+ //}}AFX_VIRTUAL
+
+// Implementation
+public:
+ virtual ~CInPlaceDateTime();
+ void EndEdit();
+
+// Generated message map functions
+protected:
+ //{{AFX_MSG(CInPlaceList)
+ afx_msg void OnKillFocus(CWnd* pNewWnd);
+ afx_msg void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags);
+ afx_msg void OnKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags);
+ afx_msg UINT OnGetDlgCode();
+ //}}AFX_MSG
+ //afx_msg void OnSelendOK();
+
+ DECLARE_MESSAGE_MAP()
+
+private:
+ CTime* m_pcTime;
+ int m_nRow;
+ int m_nCol;
+ UINT m_nLastChar;
+ BOOL m_bExitOnArrows;
+ COLORREF m_crForeClr, m_crBackClr;
+};
+
+#endif // !defined(AFX_DATETIMECELL_H__A0B7DA0A_0AFE_4D28_A00E_846C96D7507A__INCLUDED_)
diff --git a/SourceCode/Bond/Servo/GridControl/NewCellTypes/GridCellNumeric.cpp b/SourceCode/Bond/Servo/GridControl/NewCellTypes/GridCellNumeric.cpp
new file mode 100644
index 0000000..96cc411
--- /dev/null
+++ b/SourceCode/Bond/Servo/GridControl/NewCellTypes/GridCellNumeric.cpp
@@ -0,0 +1,42 @@
+// GridCellNumeric.cpp: implementation of the CGridCellNumeric class.
+//
+// Written by Andrew Truckle [ajtruckle@wsatkins.co.uk]
+//
+//////////////////////////////////////////////////////////////////////
+
+#include "stdafx.h"
+#include "GridCtrl.h"
+#include "GridCellNumeric.h"
+#include "Gridinplaceedit.h"
+
+IMPLEMENT_DYNCREATE(CGridCellNumeric, CGridCell)
+
+#ifdef _DEBUG
+#undef THIS_FILE
+static const char* THIS_FILE=__FILE__;
+#define new DEBUG_NEW
+#endif
+
+//////////////////////////////////////////////////////////////////////
+// Construction/Destruction
+//////////////////////////////////////////////////////////////////////
+
+// Create a control to do the editing
+BOOL CGridCellNumeric::Edit(int nRow, int nCol, CRect rect, CPoint /* point */, UINT nID, UINT nChar)
+{
+ m_bEditing = TRUE;
+
+ // CGridInPlaceEdit auto-deletes itself
+ m_pEditWnd = new CGridInPlaceEdit(GetGrid(), rect, /*GetStyle() |*/ ES_NUMBER, nID, nRow, nCol,
+ GetText(), nChar);
+
+ return TRUE;
+}
+
+// Cancel the editing.
+void CGridCellNumeric::EndEdit()
+{
+ if (m_pEditWnd)
+ ((CGridInPlaceEdit*)m_pEditWnd)->EndEdit();
+}
+
diff --git a/SourceCode/Bond/Servo/GridControl/NewCellTypes/GridCellNumeric.h b/SourceCode/Bond/Servo/GridControl/NewCellTypes/GridCellNumeric.h
new file mode 100644
index 0000000..3f6086a
--- /dev/null
+++ b/SourceCode/Bond/Servo/GridControl/NewCellTypes/GridCellNumeric.h
@@ -0,0 +1,26 @@
+// GridCellNumeric.h: interface for the CGridCellNumeric class.
+//
+// Written by Andrew Truckle [ajtruckle@wsatkins.co.uk]
+//
+//////////////////////////////////////////////////////////////////////
+
+#if !defined(AFX_GRIDINTEGERCELL_H__3479ED0D_B57D_4940_B83D_9E2296ED75B5__INCLUDED_)
+#define AFX_GRIDINTEGERCELL_H__3479ED0D_B57D_4940_B83D_9E2296ED75B5__INCLUDED_
+
+#if _MSC_VER > 1000
+#pragma once
+#endif // _MSC_VER > 1000
+
+#include "GridCell.h"
+
+class CGridCellNumeric : public CGridCell
+{
+ DECLARE_DYNCREATE(CGridCellNumeric)
+
+public:
+ virtual BOOL Edit(int nRow, int nCol, CRect rect, CPoint point, UINT nID, UINT nChar);
+ virtual void EndEdit();
+
+};
+
+#endif // !defined(AFX_GRIDINTEGERCELL_H__3479ED0D_B57D_4940_B83D_9E2296ED75B5__INCLUDED_)
diff --git a/SourceCode/Bond/Servo/GridControl/NewCellTypes/GridURLCell.cpp b/SourceCode/Bond/Servo/GridControl/NewCellTypes/GridURLCell.cpp
new file mode 100644
index 0000000..891ead0
--- /dev/null
+++ b/SourceCode/Bond/Servo/GridControl/NewCellTypes/GridURLCell.cpp
@@ -0,0 +1,212 @@
+// GridURLCell.cpp: implementation of the CGridURLCell class.
+//
+//////////////////////////////////////////////////////////////////////
+
+#include "stdafx.h"
+#include "GridCtrl.h"
+#include "GridURLCell.h"
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#undef THIS_FILE
+static const char* THIS_FILE = __FILE__;
+#endif
+
+IMPLEMENT_DYNCREATE(CGridURLCell, CGridCell)
+
+#ifndef _WIN32_WCE
+HCURSOR CGridURLCell::g_hLinkCursor = NULL;
+#endif
+
+// Possible prefixes that indicate a hyperlink
+URLStruct CGridURLCell::g_szURIprefixes[] = {
+ { _T("www."), _tcslen(_T("www.")) },
+ { _T("http:"), _tcslen(_T("http:")) },
+ { _T("mailto:"), _tcslen(_T("mailto:")) },
+ { _T("ftp:"), _tcslen(_T("ftp:")) },
+ { _T("https:"), _tcslen(_T("https:")) },
+ { _T("news:"), _tcslen(_T("news:")) },
+ { _T("gopher:"), _tcslen(_T("gopher:")) },
+ { _T("telnet:"), _tcslen(_T("telnet:")) },
+ { _T("url:"), _tcslen(_T("url:")) },
+ { _T("file:"), _tcslen(_T("file:")) },
+ { _T("ftp."), _tcslen(_T("ftp.")) }
+};
+
+//////////////////////////////////////////////////////////////////////
+// Construction/Destruction
+//////////////////////////////////////////////////////////////////////
+
+CGridURLCell::CGridURLCell()
+{
+#ifndef _WIN32_WCE
+ g_hLinkCursor = GetHandCursor();
+#endif
+ m_bLaunchUrl = TRUE;
+ m_clrUrl = GetSysColor(COLOR_HIGHLIGHT);
+}
+
+CGridURLCell::~CGridURLCell()
+{
+}
+
+BOOL CGridURLCell::Draw(CDC* pDC, int nRow, int nCol, CRect rect, BOOL bEraseBkgnd)
+{
+ // If url is present then change text color
+ if (HasUrl(GetText()))
+ SetTextClr(m_clrUrl);
+
+ // Good a place as any to store the bounds of the rect
+ m_Rect = rect;
+
+ return CGridCell::Draw(pDC, nRow, nCol, rect, bEraseBkgnd);
+}
+
+#pragma warning(disable:4100)
+BOOL CGridURLCell::Edit(int nRow, int nCol, CRect rect, CPoint point, UINT nID, UINT nChar)
+{
+ return FALSE;
+}
+#pragma warning(default:4100)
+
+void CGridURLCell::OnClick(CPoint PointCellRelative)
+{
+#ifndef _WIN32_WCE
+ CString strURL;
+ if (GetAutoLaunchUrl() && OverURL(PointCellRelative, strURL))
+ ShellExecute(NULL, _T("open"), strURL, NULL,NULL, SW_SHOW);
+#endif
+}
+
+// Return TRUE if you set the cursor
+BOOL CGridURLCell::OnSetCursor()
+{
+#ifndef _WIN32_WCE
+ CString strURL;
+ CPoint pt(GetMessagePos());
+ GetGrid()->ScreenToClient(&pt);
+ pt = pt - m_Rect.TopLeft();
+
+ if (OverURL(pt, strURL))
+ {
+ SetCursor(g_hLinkCursor);
+ return TRUE;
+ }
+ else
+#endif
+ return CGridCell::OnSetCursor();
+}
+
+#ifndef _WIN32_WCE
+HCURSOR CGridURLCell::GetHandCursor()
+{
+ if (g_hLinkCursor == NULL) // No cursor handle - load our own
+ {
+ // Get the windows directory
+ CString strWndDir;
+ GetWindowsDirectory(strWndDir.GetBuffer(MAX_PATH), MAX_PATH);
+ strWndDir.ReleaseBuffer();
+
+ strWndDir += _T("\\winhlp32.exe");
+ // This retrieves cursor #106 from winhlp32.exe, which is a hand pointer
+ HMODULE hModule = LoadLibrary(strWndDir);
+ if( hModule )
+ {
+ HCURSOR hHandCursor = ::LoadCursor(hModule, MAKEINTRESOURCE(106));
+ if( hHandCursor )
+ {
+ g_hLinkCursor = CopyCursor(hHandCursor);
+ }
+ }
+ FreeLibrary(hModule);
+ }
+
+ return g_hLinkCursor;
+}
+#endif
+
+////////////////////////////////////////////////////////////////////////////////////////////
+// Helper functions
+
+BOOL CGridURLCell::HasUrl(CString str)
+{
+ int nNumPrefixes = sizeof(g_szURIprefixes) / sizeof(g_szURIprefixes[0]);
+ for (int i = 0; i < nNumPrefixes; i++)
+ //if (str.Left(g_szURIprefixes[i].nLength) == g_szURIprefixes[i].szURLPrefix)
+ if (str.Find(g_szURIprefixes[i].szURLPrefix) >= 0)
+ return TRUE;
+
+ return FALSE;
+}
+
+// here we figure out if we are over a URL or not
+BOOL CGridURLCell::OverURL(CPoint& pt, CString& strURL)
+{
+ //TRACE2("Checking point %d,%d\n",pt.x,pt.y);
+
+ BOOL bOverURL = FALSE;
+ CSize size = GetTextExtent(GetText());
+
+ // Add left of cell so we know if we clicked on text or not
+ pt.x += m_Rect.left;
+ CPoint center = m_Rect.CenterPoint();
+
+ if ((m_nFormat & DT_RIGHT) && pt.x >= (m_Rect.right - size.cx))
+ {
+ bOverURL = TRUE;
+ }
+ else if ((m_nFormat & DT_CENTER) &&
+ ((center.x - (size.cx/2)) <= pt.x) && (pt.x <= (center.x + (size.cx/2))) )
+ {
+ bOverURL = TRUE;
+ }
+ else if (pt.x <= (size.cx + m_Rect.left))
+ {
+ bOverURL = TRUE;
+ }
+
+ if (!bOverURL)
+ return FALSE;
+
+ // We are over text - but are we over a URL?
+ bOverURL = FALSE;
+ strURL = GetText();
+
+ // Use float, otherwise we get an incorrect letter from the point
+ float width = (float)size.cx/(float)strURL.GetLength();
+
+ // remove left of cell so we have original point again
+ pt.x -= m_Rect.left;
+ if (m_nFormat & DT_RIGHT)
+ {
+ int wide = m_Rect.Width() - size.cx;
+ pt.x -= wide;
+ if (pt.x <= 0)
+ return FALSE;
+ }
+
+ if (m_nFormat & DT_CENTER)
+ {
+ int wide = m_Rect.Width() - size.cx;
+ pt.x -= (wide/2);
+ if (pt.x <= 0 || pt.x > (size.cx + (wide/2)))
+ return FALSE;
+ }
+
+ // Turn point into a letter
+ int ltrs = (int)((float)pt.x/width);
+#if !defined(_WIN32_WCE) || (_WIN32_WCE > 210)
+ // Find spaces before and after letter, process text between
+ int endSpace = strURL.Find(_T(' '), ltrs);
+ if (endSpace != -1)
+ strURL.Delete(endSpace, strURL.GetLength()-endSpace);
+
+ int beginSpace = strURL.ReverseFind(_T(' '));
+ if (beginSpace != -1)
+ strURL.Delete(0, ++beginSpace);
+#endif
+
+ // Does text have url
+ return HasUrl(strURL);
+}
+
diff --git a/SourceCode/Bond/Servo/GridControl/NewCellTypes/GridURLCell.h b/SourceCode/Bond/Servo/GridControl/NewCellTypes/GridURLCell.h
new file mode 100644
index 0000000..1960250
--- /dev/null
+++ b/SourceCode/Bond/Servo/GridControl/NewCellTypes/GridURLCell.h
@@ -0,0 +1,55 @@
+// GridURLCell.h: interface for the CGridURLCell class.
+//
+//////////////////////////////////////////////////////////////////////
+
+#if !defined(AFX_GRIDURLCELL_H__9F4A50B4_D773_11D3_A439_F7E60631F563__INCLUDED_)
+#define AFX_GRIDURLCELL_H__9F4A50B4_D773_11D3_A439_F7E60631F563__INCLUDED_
+
+#if _MSC_VER > 1000
+#pragma once
+#endif // _MSC_VER > 1000
+
+#include "GridCell.h"
+
+typedef struct {
+ LPCTSTR szURLPrefix;
+ size_t nLength;
+} URLStruct;
+
+
+
+class CGridURLCell : public CGridCell
+{
+ DECLARE_DYNCREATE(CGridURLCell)
+
+public:
+ CGridURLCell();
+ virtual ~CGridURLCell();
+
+ virtual BOOL Draw(CDC* pDC, int nRow, int nCol, CRect rect, BOOL bEraseBkgnd = TRUE);
+ virtual BOOL Edit(int nRow, int nCol, CRect rect, CPoint point, UINT nID, UINT nChar);
+ virtual LPCTSTR GetTipText() { return NULL; }
+ void SetAutoLaunchUrl(BOOL bLaunch = TRUE) { m_bLaunchUrl = bLaunch; }
+ BOOL GetAutoLaunchUrl() { return m_bLaunchUrl; }
+
+protected:
+ virtual BOOL OnSetCursor();
+ virtual void OnClick(CPoint PointCellRelative);
+
+ BOOL HasUrl(CString str);
+ BOOL OverURL(CPoint& pt, CString& strURL);
+
+protected:
+#ifndef _WIN32_WCE
+ static HCURSOR g_hLinkCursor; // Hyperlink mouse cursor
+ HCURSOR GetHandCursor();
+#endif
+ static URLStruct g_szURIprefixes[];
+
+protected:
+ COLORREF m_clrUrl;
+ BOOL m_bLaunchUrl;
+ CRect m_Rect;
+};
+
+#endif // !defined(AFX_GRIDURLCELL_H__9F4A50B4_D773_11D3_A439_F7E60631F563__INCLUDED_)
diff --git a/SourceCode/Bond/Servo/GridControl/TitleTip.cpp b/SourceCode/Bond/Servo/GridControl/TitleTip.cpp
new file mode 100644
index 0000000..b821a82
--- /dev/null
+++ b/SourceCode/Bond/Servo/GridControl/TitleTip.cpp
@@ -0,0 +1,341 @@
+////////////////////////////////////////////////////////////////////////////
+// TitleTip.cpp : implementation file
+//
+// Based on code by Zafir Anjum
+//
+// Adapted by Chris Maunder <cmaunder@mail.com>
+// Copyright (c) 1998-2002. All Rights Reserved.
+//
+// This code may be used in compiled form in any way you desire. This
+// file may be redistributed unmodified by any means PROVIDING it is
+// not sold for profit without the authors written consent, and
+// providing that this notice and the authors name and all copyright
+// notices remains intact.
+//
+// An email letting me know how you are using it would be nice as well.
+//
+// This file is provided "as is" with no expressed or implied warranty.
+// The author accepts no liability for any damage/loss of business that
+// this product may cause.
+//
+// For use with CGridCtrl v2.20+
+//
+// History
+// 10 Apr 1999 Now accepts a LOGFONT pointer and
+// a tracking rect in Show(...) (Chris Maunder)
+// 18 Apr 1999 Resource leak in Show fixed by Daniel Gehriger
+// 8 Mar 2000 Added double-click fix found on codeguru
+// web site but forgot / can't find who contributed it
+// 28 Mar 2000 Aqiruse (marked with //FNA)
+// Titletips now use cell color
+// 18 Jun 2000 Delayed window creation added
+//
+/////////////////////////////////////////////////////////////////////////////
+
+#include "stdafx.h"
+#include "gridctrl.h"
+
+#ifndef GRIDCONTROL_NO_TITLETIPS
+
+#include "TitleTip.h"
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#undef THIS_FILE
+static const char* THIS_FILE = __FILE__;
+#endif
+
+/////////////////////////////////////////////////////////////////////////////
+// CTitleTip
+
+CTitleTip::CTitleTip()
+{
+ // Register the window class if it has not already been registered.
+ WNDCLASS wndcls;
+ HINSTANCE hInst = AfxGetInstanceHandle();
+ if(!(::GetClassInfo(hInst, TITLETIP_CLASSNAME, &wndcls)))
+ {
+ // otherwise we need to register a new class
+ wndcls.style = CS_SAVEBITS;
+ wndcls.lpfnWndProc = ::DefWindowProc;
+ wndcls.cbClsExtra = wndcls.cbWndExtra = 0;
+ wndcls.hInstance = hInst;
+ wndcls.hIcon = NULL;
+ wndcls.hCursor = LoadCursor( hInst, IDC_ARROW );
+ wndcls.hbrBackground = (HBRUSH)(COLOR_INFOBK +1);
+ wndcls.lpszMenuName = NULL;
+ wndcls.lpszClassName = TITLETIP_CLASSNAME;
+
+ if (!AfxRegisterClass(&wndcls))
+ AfxThrowResourceException();
+ }
+
+ m_dwLastLButtonDown = ULONG_MAX;
+ m_dwDblClickMsecs = GetDoubleClickTime();
+ m_bCreated = FALSE;
+ m_pParentWnd = NULL;
+}
+
+CTitleTip::~CTitleTip()
+{
+}
+
+
+BEGIN_MESSAGE_MAP(CTitleTip, CWnd)
+ //{{AFX_MSG_MAP(CTitleTip)
+ ON_WM_MOUSEMOVE()
+ //}}AFX_MSG_MAP
+END_MESSAGE_MAP()
+
+
+/////////////////////////////////////////////////////////////////////////////
+// CTitleTip message handlers
+
+BOOL CTitleTip::Create(CWnd * pParentWnd)
+{
+// ASSERT_VALID(pParentWnd);
+
+ // Already created?
+ if (m_bCreated)
+ return TRUE;
+
+ DWORD dwStyle = WS_BORDER | WS_POPUP;
+ DWORD dwExStyle = WS_EX_TOOLWINDOW | WS_EX_TOPMOST;
+ m_pParentWnd = pParentWnd;
+
+ m_bCreated = CreateEx(dwExStyle, TITLETIP_CLASSNAME, NULL, dwStyle,
+ CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
+ NULL, NULL, NULL );
+
+ return m_bCreated;
+}
+
+BOOL CTitleTip::DestroyWindow()
+{
+ m_bCreated = FALSE;
+
+ return CWnd::DestroyWindow();
+}
+
+// Show - Show the titletip if needed
+// rectTitle - The rectangle within which the original
+// title is constrained - in client coordinates
+// lpszTitleText - The text to be displayed
+// xoffset - Number of pixel that the text is offset from
+// left border of the cell
+void CTitleTip::Show(CRect rectTitle, LPCTSTR lpszTitleText, int xoffset /*=0*/,
+ LPRECT lpHoverRect /*=NULL*/,
+ const LOGFONT* lpLogFont /*=NULL*/,
+ COLORREF crTextClr /* CLR_DEFAULT */,
+ COLORREF crBackClr /* CLR_DEFAULT */)
+{
+ if (!IsWindow(m_hWnd))
+ Create(m_pParentWnd);
+
+// ASSERT( ::IsWindow( GetSafeHwnd() ) );
+
+ if (rectTitle.IsRectEmpty())
+ return;
+
+ // If titletip is already displayed, don't do anything.
+ if( IsWindowVisible() )
+ return;
+
+ m_rectHover = (lpHoverRect != NULL)? lpHoverRect : rectTitle;
+ m_rectHover.right++; m_rectHover.bottom++;
+
+ m_pParentWnd->ClientToScreen( m_rectHover );
+ ScreenToClient( m_rectHover );
+
+ // Do not display the titletip is app does not have focus
+ if( GetFocus() == NULL )
+ return;
+
+ // Define the rectangle outside which the titletip will be hidden.
+ // We add a buffer of one pixel around the rectangle
+ m_rectTitle.top = -1;
+ m_rectTitle.left = -xoffset-1;
+ m_rectTitle.right = rectTitle.Width()-xoffset;
+ m_rectTitle.bottom = rectTitle.Height()+1;
+
+ // Determine the width of the text
+ m_pParentWnd->ClientToScreen( rectTitle );
+
+ CClientDC dc(this);
+ CString strTitle = _T("");
+ strTitle += _T(" ");
+ strTitle += lpszTitleText;
+ strTitle += _T(" ");
+
+ CFont font, *pOldFont = NULL;
+ if (lpLogFont)
+ {
+ font.CreateFontIndirect(lpLogFont);
+ pOldFont = dc.SelectObject( &font );
+ }
+ else
+ {
+ // use same font as ctrl
+ pOldFont = dc.SelectObject( m_pParentWnd->GetFont() );
+ }
+
+ CSize size = dc.GetTextExtent( strTitle );
+
+ TEXTMETRIC tm;
+ dc.GetTextMetrics(&tm);
+ size.cx += tm.tmOverhang;
+
+ CRect rectDisplay = rectTitle;
+ rectDisplay.left += xoffset;
+ rectDisplay.right = rectDisplay.left + size.cx + xoffset;
+
+ // Do not display if the text fits within available space
+ if ( rectDisplay.right > rectTitle.right-xoffset )
+ {
+ // Show the titletip
+ SetWindowPos( &wndTop, rectDisplay.left, rectDisplay.top,
+ rectDisplay.Width(), rectDisplay.Height(),
+ SWP_SHOWWINDOW|SWP_NOACTIVATE );
+
+ // FNA - handle colors correctly
+ if (crBackClr != CLR_DEFAULT)
+ {
+ CBrush backBrush(crBackClr);
+ CBrush* pOldBrush = dc.SelectObject(&backBrush);
+ CRect rect;
+ dc.GetClipBox(&rect); // Erase the area needed
+
+ dc.PatBlt(rect.left, rect.top, rect.Width(), rect.Height(), PATCOPY);
+ dc.SelectObject(pOldBrush);
+ }
+ // Set color
+ if (crTextClr != CLR_DEFAULT)//FNA
+ dc.SetTextColor(crTextClr);//FA
+
+ dc.SetBkMode( TRANSPARENT );
+ dc.TextOut( 0, 0, strTitle );
+ SetCapture();
+ }
+
+ dc.SelectObject( pOldFont );
+}
+
+void CTitleTip::Hide()
+{
+ if (!::IsWindow(GetSafeHwnd()))
+ return;
+
+ if (GetCapture()->GetSafeHwnd() == GetSafeHwnd())
+ ReleaseCapture();
+
+ ShowWindow( SW_HIDE );
+}
+
+void CTitleTip::OnMouseMove(UINT nFlags, CPoint point)
+{
+ if (!m_rectHover.PtInRect(point))
+ {
+ Hide();
+
+ // Forward the message
+ ClientToScreen( &point );
+ CWnd *pWnd = WindowFromPoint( point );
+ if ( pWnd == this )
+ pWnd = m_pParentWnd;
+
+ int hittest = (int)pWnd->SendMessage(WM_NCHITTEST,0,MAKELONG(point.x,point.y));
+
+ if (hittest == HTCLIENT) {
+ pWnd->ScreenToClient( &point );
+ pWnd->PostMessage( WM_MOUSEMOVE, nFlags, MAKELONG(point.x,point.y) );
+ } else {
+ pWnd->PostMessage( WM_NCMOUSEMOVE, hittest, MAKELONG(point.x,point.y) );
+ }
+ }
+}
+
+BOOL CTitleTip::PreTranslateMessage(MSG* pMsg)
+{
+ // Used to qualify WM_LBUTTONDOWN messages as double-clicks
+ DWORD dwTick=0;
+ BOOL bDoubleClick=FALSE;
+
+ CWnd *pWnd;
+ int hittest;
+ switch (pMsg->message)
+ {
+ case WM_LBUTTONDOWN:
+ // Get tick count since last LButtonDown
+ dwTick = GetTickCount();
+ bDoubleClick = ((dwTick - m_dwLastLButtonDown) <= m_dwDblClickMsecs);
+ m_dwLastLButtonDown = dwTick;
+ // NOTE: DO NOT ADD break; STATEMENT HERE! Let code fall through
+
+ case WM_RBUTTONDOWN:
+ case WM_MBUTTONDOWN:
+ {
+ POINTS pts = MAKEPOINTS( pMsg->lParam );
+ POINT point;
+ point.x = pts.x;
+ point.y = pts.y;
+
+ ClientToScreen( &point );
+ Hide();
+
+ pWnd = WindowFromPoint( point );
+ if (!pWnd)
+ return CWnd::PreTranslateMessage(pMsg);
+
+ if( pWnd->GetSafeHwnd() == GetSafeHwnd())
+ pWnd = m_pParentWnd;
+
+ hittest = (int)pWnd->SendMessage(WM_NCHITTEST,0,MAKELONG(point.x,point.y));
+
+ if (hittest == HTCLIENT)
+ {
+ pWnd->ScreenToClient( &point );
+ pMsg->lParam = MAKELONG(point.x,point.y);
+ }
+ else
+ {
+ switch (pMsg->message) {
+ case WM_LBUTTONDOWN:
+ pMsg->message = WM_NCLBUTTONDOWN;
+ break;
+ case WM_RBUTTONDOWN:
+ pMsg->message = WM_NCRBUTTONDOWN;
+ break;
+ case WM_MBUTTONDOWN:
+ pMsg->message = WM_NCMBUTTONDOWN;
+ break;
+ }
+ pMsg->wParam = hittest;
+ pMsg->lParam = MAKELONG(point.x,point.y);
+ }
+
+
+ // If this is the 2nd WM_LBUTTONDOWN in x milliseconds,
+ // post a WM_LBUTTONDBLCLK message instead of a single click.
+ pWnd->PostMessage( bDoubleClick ? WM_LBUTTONDBLCLK : pMsg->message,
+ pMsg->wParam,
+ pMsg->lParam);
+ return TRUE;
+ }
+
+ case WM_KEYDOWN:
+ case WM_SYSKEYDOWN:
+ Hide();
+ m_pParentWnd->PostMessage( pMsg->message, pMsg->wParam, pMsg->lParam );
+ return TRUE;
+ }
+
+ if( GetFocus() == NULL )
+ {
+ Hide();
+ return TRUE;
+ }
+
+ return CWnd::PreTranslateMessage(pMsg);
+}
+
+#endif // GRIDCONTROL_NO_TITLETIPS
\ No newline at end of file
diff --git a/SourceCode/Bond/Servo/GridControl/TitleTip.h b/SourceCode/Bond/Servo/GridControl/TitleTip.h
new file mode 100644
index 0000000..63d6d47
--- /dev/null
+++ b/SourceCode/Bond/Servo/GridControl/TitleTip.h
@@ -0,0 +1,87 @@
+/////////////////////////////////////////////////////////////////////////////
+// Titletip.h : header file
+//
+// MFC Grid Control - cell titletips
+//
+// Written by Chris Maunder <chris@codeproject.com>
+// Copyright (c) 1998-2005. All Rights Reserved.
+//
+// This code may be used in compiled form in any way you desire. This
+// file may be redistributed unmodified by any means PROVIDING it is
+// not sold for profit without the authors written consent, and
+// providing that this notice and the authors name and all copyright
+// notices remains intact.
+//
+// An email letting me know how you are using it would be nice as well.
+//
+// This file is provided "as is" with no expressed or implied warranty.
+// The author accepts no liability for any damage/loss of business that
+// this product may cause.
+//
+// For use with CGridCtrl v2.10+
+//
+//////////////////////////////////////////////////////////////////////
+
+#if !defined(AFX_TITLETIP_H__C7165DA1_187F_11D1_992F_895E185F9C72__INCLUDED_)
+#define AFX_TITLETIP_H__C7165DA1_187F_11D1_992F_895E185F9C72__INCLUDED_
+
+#if _MSC_VER >= 1000
+#pragma once
+#endif // _MSC_VER >= 1000
+
+#define TITLETIP_CLASSNAME _T("ZTitleTip")
+
+/////////////////////////////////////////////////////////////////////////////
+// CTitleTip window
+
+class CTitleTip : public CWnd
+{
+// Construction
+public:
+ CTitleTip();
+ virtual ~CTitleTip();
+ virtual BOOL Create( CWnd *pParentWnd);
+
+// Attributes
+public:
+ void SetParentWnd(CWnd* pParentWnd) { m_pParentWnd = pParentWnd; }
+ CWnd* GetParentWnd() { return m_pParentWnd; }
+
+// Operations
+public:
+ void Show(CRect rectTitle, LPCTSTR lpszTitleText,
+ int xoffset = 0, LPRECT lpHoverRect = NULL,
+ const LOGFONT* lpLogFont = NULL,
+ COLORREF crTextClr = CLR_DEFAULT, COLORREF crBackClr = CLR_DEFAULT);
+ void Hide();
+
+// Overrides
+ // ClassWizard generated virtual function overrides
+ //{{AFX_VIRTUAL(CTitleTip)
+ public:
+ virtual BOOL PreTranslateMessage(MSG* pMsg);
+ virtual BOOL DestroyWindow();
+ //}}AFX_VIRTUAL
+
+// Implementation
+protected:
+ CWnd *m_pParentWnd;
+ CRect m_rectTitle;
+ CRect m_rectHover;
+ DWORD m_dwLastLButtonDown;
+ DWORD m_dwDblClickMsecs;
+ BOOL m_bCreated;
+
+ // Generated message map functions
+protected:
+ //{{AFX_MSG(CTitleTip)
+ afx_msg void OnMouseMove(UINT nFlags, CPoint point);
+ //}}AFX_MSG
+ DECLARE_MESSAGE_MAP()
+};
+
+/////////////////////////////////////////////////////////////////////////////
+//{{AFX_INSERT_LOCATION}}
+// Microsoft Developer Studio will insert additional declarations immediately before the previous line.
+
+#endif // !defined(AFX_TITLETIP_H__C7165DA1_187F_11D1_992F_895E185F9C72__INCLUDED_)
diff --git a/SourceCode/Bond/Servo/PageRobotCmd.cpp b/SourceCode/Bond/Servo/PageRobotCmd.cpp
index 001135a..c498aa2 100644
--- a/SourceCode/Bond/Servo/PageRobotCmd.cpp
+++ b/SourceCode/Bond/Servo/PageRobotCmd.cpp
@@ -10,18 +10,18 @@
// CPageRobotCmd 瀵硅瘽妗�
std::map<CString, int> g_deviceSlotCount = {
- {_T("PORT 1"), 1},
- {_T("PORT 2"), 1},
- {_T("PORT 3"), 1},
- {_T("PORT 4"), 1},
+ {_T("PORT 1"), 8},
+ {_T("PORT 2"), 8},
+ {_T("PORT 3"), 8},
+ {_T("PORT 4"), 8},
{_T("RB1"), 1},
{_T("RB2"), 1},
{_T("ALIGN"), 1},
{_T("FLIP"), 1},
- {_T("VAC BAKE"), 2},
+ {_T("VAC BAKE"), 4},
{_T("BONDER1"), 2},
{_T("BONDER2"), 2},
- {_T("POST BAKE(COOLING)"), 4},
+ {_T("POST BAKE(COOLING)"), 2},
{_T("MEASUREMENT"), 1}
};
diff --git a/SourceCode/Bond/Servo/PortConfigurationDlg.cpp b/SourceCode/Bond/Servo/PortConfigurationDlg.cpp
new file mode 100644
index 0000000..79a1e11
--- /dev/null
+++ b/SourceCode/Bond/Servo/PortConfigurationDlg.cpp
@@ -0,0 +1,146 @@
+锘�// PortConfigurationDlg.cpp: 瀹炵幇鏂囦欢
+//
+
+#include "stdafx.h"
+#include "Servo.h"
+#include "afxdialogex.h"
+#include "PortConfigurationDlg.h"
+#include "NewCellTypes/GridCellCheck.h"
+#include "NewCellTypes/GridCellCombo.h"
+#include "NewCellTypes/GridCellNumeric.h"
+
+
+// CPortConfigurationDlg 瀵硅瘽妗�
+
+IMPLEMENT_DYNAMIC(CPortConfigurationDlg, CDialogEx)
+
+CPortConfigurationDlg::CPortConfigurationDlg(CWnd* pParent /*=nullptr*/)
+ : CDialogEx(IDD_DIALOG_PORT_CONFIGURATION, pParent)
+{
+
+}
+
+CPortConfigurationDlg::~CPortConfigurationDlg()
+{
+}
+
+void CPortConfigurationDlg::InitGrid()
+{
+ if (m_wndGrid.GetSafeHwnd() == NULL) {
+ return;
+ }
+
+ const int nCols = 3;
+ const int nFixRows = 1;
+ const int nRows = 9;
+
+ int nColIdx = 0;
+ m_wndGrid.DeleteAllItems();
+ m_wndGrid.SetVirtualMode(FALSE);
+
+ // 璁剧疆鏍峰紡棰滆壊
+ m_wndGrid.GetDefaultCell(TRUE, FALSE)->SetBackClr(g_nGridFixCellColor);
+ m_wndGrid.GetDefaultCell(FALSE, TRUE)->SetBackClr(g_nGridFixCellColor);
+ m_wndGrid.GetDefaultCell(FALSE, FALSE)->SetBackClr(g_nGridCellColor);
+ m_wndGrid.SetFixedTextColor(g_nGridFixFontColor);
+
+ // 琛屽垪鏁伴噺
+ m_wndGrid.SetRowCount(nRows);
+ m_wndGrid.SetColumnCount(nCols);
+ m_wndGrid.SetFixedRowCount(nFixRows);
+ m_wndGrid.SetFixedColumnCount(0);
+
+ // 璁剧疆鍒楀
+ m_wndGrid.SetColumnWidth(nColIdx, 50);
+ m_wndGrid.SetItemText(0, nColIdx++, _T("Slot ID"));
+ m_wndGrid.SetColumnWidth(nColIdx, 150);
+ m_wndGrid.SetItemText(0, nColIdx++, _T("EQ Recipe"));
+ m_wndGrid.SetColumnWidth(nColIdx, 150);
+ m_wndGrid.SetItemText(0, nColIdx++, _T("Panel ID"));
+ m_wndGrid.SetColumnWidth(nColIdx, 60);
+ m_wndGrid.SetItemText(0, nColIdx++, _T("鍚敤"));
+
+ // 璁剧疆琛屼负鏍峰紡
+ m_wndGrid.SetFixedRowSelection(FALSE);
+ m_wndGrid.SetFixedColumnSelection(FALSE);
+ m_wndGrid.SetEditable(TRUE);
+ m_wndGrid.SetRowResize(FALSE);
+ m_wndGrid.SetColumnResize(TRUE);
+ m_wndGrid.SetListMode(TRUE);
+ m_wndGrid.EnableSelection(TRUE);
+ m_wndGrid.SetSingleRowSelection(TRUE);
+ m_wndGrid.ExpandColumnsToFit(TRUE);
+ m_wndGrid.ExpandLastColumn();
+
+ // 鑷姩璁$畻骞惰缃瘡琛岄珮搴�
+ CRect rcClient;
+ m_wndGrid.GetClientRect(&rcClient);
+ int nAvailableHeight = rcClient.Height();
+ int nEachRowHeight = max(24, nAvailableHeight / nRows);
+
+ for (int i = 0; i < nRows; ++i) {
+ m_wndGrid.SetRowHeight(i, nEachRowHeight);
+ }
+
+ FillGrid();
+}
+
+void CPortConfigurationDlg::FillGrid()
+{
+ //CStringArray recipeOptions;
+ //recipeOptions.Add(_T("Recipe A"));
+ //recipeOptions.Add(_T("Recipe B"));
+ //recipeOptions.Add(_T("Recipe C"));
+
+ for (int i = 1; i < 9; ++i) {
+ CString strIndex;
+ strIndex.Format(_T("%d"), i);
+ m_wndGrid.SetItemText(i, 0, strIndex);
+ m_wndGrid.SetItemState(i, 0, GVIS_READONLY);
+
+ // EQ Recipe - ComboBox
+ //if (m_wndGrid.SetCellType(i, 1, RUNTIME_CLASS(CGridCellCombo))) {
+ // CGridCellCombo* pCell = static_cast<CGridCellCombo*>(m_wndGrid.GetCell(i, 1));
+ // pCell->SetOptions(recipeOptions);
+ // pCell->SetStyle(CBS_DROPDOWNLIST);
+ //}
+ //m_wndGrid.SetItemText(i, 1, recipeOptions[0]);
+
+ // Panel ID - 鍙紪杈�
+ m_wndGrid.SetItemText(i, 1, _T(""));
+
+ // Checkbox
+ m_wndGrid.SetCellType(i, 2, RUNTIME_CLASS(CGridCellCheck));
+ CGridCellCheck* pCheck = static_cast<CGridCellCheck*>(m_wndGrid.GetCell(i, 2));
+ if (pCheck) {
+ pCheck->SetCheck(FALSE);
+ }
+ }
+
+ m_wndGrid.Invalidate();
+ m_wndGrid.UpdateWindow();
+}
+
+void CPortConfigurationDlg::DoDataExchange(CDataExchange* pDX)
+{
+ DDX_Control(pDX, IDC_GRID_PANEL_RECIPE, m_wndGrid);
+ CDialogEx::DoDataExchange(pDX);
+}
+
+
+BEGIN_MESSAGE_MAP(CPortConfigurationDlg, CDialogEx)
+END_MESSAGE_MAP()
+
+
+// CPortConfigurationDlg 娑堟伅澶勭悊绋嬪簭
+
+BOOL CPortConfigurationDlg::OnInitDialog()
+{
+ CDialogEx::OnInitDialog();
+
+ // TODO: 鍦ㄦ娣诲姞棰濆鐨勫垵濮嬪寲
+ InitGrid();
+
+ return TRUE; // return TRUE unless you set the focus to a control
+ // 寮傚父: OCX 灞炴�ч〉搴旇繑鍥� FALSE
+}
diff --git a/SourceCode/Bond/Servo/PortConfigurationDlg.h b/SourceCode/Bond/Servo/PortConfigurationDlg.h
new file mode 100644
index 0000000..ac7a710
--- /dev/null
+++ b/SourceCode/Bond/Servo/PortConfigurationDlg.h
@@ -0,0 +1,30 @@
+锘�#pragma once
+#include "afxdialogex.h"
+#include "GridCtrl.h"
+
+// CPortConfigurationDlg 瀵硅瘽妗�
+
+class CPortConfigurationDlg : public CDialogEx
+{
+ DECLARE_DYNAMIC(CPortConfigurationDlg)
+
+public:
+ CPortConfigurationDlg(CWnd* pParent = nullptr); // 鏍囧噯鏋勯�犲嚱鏁�
+ virtual ~CPortConfigurationDlg();
+
+// 瀵硅瘽妗嗘暟鎹�
+#ifdef AFX_DESIGN_TIME
+ enum { IDD = IDD_DIALOG_PORT_CONFIGURATION };
+#endif
+
+protected:
+ virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 鏀寔
+ virtual BOOL OnInitDialog();
+ DECLARE_MESSAGE_MAP()
+
+private:
+ CGridCtrl m_wndGrid;
+
+ void InitGrid();
+ void FillGrid();
+};
diff --git a/SourceCode/Bond/Servo/Servo.cpp b/SourceCode/Bond/Servo/Servo.cpp
index 3b5e1c5..18a95a1 100644
--- a/SourceCode/Bond/Servo/Servo.cpp
+++ b/SourceCode/Bond/Servo/Servo.cpp
@@ -8,7 +8,7 @@
#include "ServoGraph.h"
#include "AlarmManager.h"
#include "SECSRuntimeManager.h"
-#include "ProductionLogManager.h"
+#include "TransferManager.h"
#include "VerticalLine.h"
#include "EqsGraphWnd.h"
#include "MapPosWnd.h"
@@ -132,22 +132,6 @@
}
AlarmManager::getInstance().insertMockData();
-
- // 初始化生产履历管理器
- //try {
- // if (!ProductionLogManager::getInstance().initProductionTable()) {
- // AfxMessageBox("初始化生产履历管理器失败!");
- // return FALSE;
- // }
- //}
- //catch (const std::exception& ex) {
- // CString errorMsg;
- // errorMsg.Format(_T("初始化生产履历管理器失败:%s"), CString(ex.what()));
- // AfxMessageBox(errorMsg, MB_ICONERROR);
- // return FALSE;
- //}
-
-
// 初始化SECS运行设置管理库
try {
if (!SECSRuntimeManager::getInstance().initRuntimeSetting()) {
@@ -158,6 +142,20 @@
catch (const std::exception& ex) {
CString errorMsg;
errorMsg.Format(_T("初始化SECS运行设置失败:%s"), CString(ex.what()));
+ AfxMessageBox(errorMsg, MB_ICONERROR);
+ return FALSE;
+ }
+
+ // 初始化搬运记录管理库
+ try {
+ if (!TransferManager::getInstance().initTransferTable()) {
+ AfxMessageBox("初始化搬运记录管理库设置失败!");
+ return FALSE;
+ }
+ }
+ catch (const std::exception& ex) {
+ CString errorMsg;
+ errorMsg.Format(_T("初始化搬运记录管理库设置失败:%s"), CString(ex.what()));
AfxMessageBox(errorMsg, MB_ICONERROR);
return FALSE;
}
@@ -205,12 +203,12 @@
// 销毁报警表
AlarmManager::getInstance().termAlarmTable();
- // 销毁生产表
- ProductionLogManager::getInstance().termProductionTable();
-
// 销毁SECS运行设置管理库
SECSRuntimeManager::getInstance().termRuntimeSetting();
+ // 销毁搬运记录管理库
+ TransferManager::getInstance().termTransferTable();
+
return CWinApp::ExitInstance();
}
diff --git a/SourceCode/Bond/Servo/Servo.rc b/SourceCode/Bond/Servo/Servo.rc
index 7bdf825..140d51f 100644
--- a/SourceCode/Bond/Servo/Servo.rc
+++ b/SourceCode/Bond/Servo/Servo.rc
Binary files differ
diff --git a/SourceCode/Bond/Servo/Servo.vcxproj b/SourceCode/Bond/Servo/Servo.vcxproj
index 8fac7f2..11eb375 100644
--- a/SourceCode/Bond/Servo/Servo.vcxproj
+++ b/SourceCode/Bond/Servo/Servo.vcxproj
@@ -115,7 +115,7 @@
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>_WINDOWS;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
- <AdditionalIncludeDirectories>.;..;..\DatabaseSDK\include;..\MELSECSDK\include;.\CCLinkPerformance;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>.;..;..\DatabaseSDK\include;..\MELSECSDK\include;.\CCLinkPerformance;.\GridControl;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
@@ -204,6 +204,20 @@
<ClInclude Include="CRobotCmdTestDlg.h" />
<ClInclude Include="CPagePortStatus.h" />
<ClInclude Include="CPortStatusReport.h" />
+ <ClInclude Include="GridControl\CellRange.h" />
+ <ClInclude Include="GridControl\GridCell.h" />
+ <ClInclude Include="GridControl\GridCellBase.h" />
+ <ClInclude Include="GridControl\GridCellButton.h" />
+ <ClInclude Include="GridControl\GridCtrl.h" />
+ <ClInclude Include="GridControl\GridDropTarget.h" />
+ <ClInclude Include="GridControl\GridInPlaceEdit.h" />
+ <ClInclude Include="GridControl\GridMemDC.h" />
+ <ClInclude Include="GridControl\NewCellTypes\GridCellCheck.h" />
+ <ClInclude Include="GridControl\NewCellTypes\GridCellCombo.h" />
+ <ClInclude Include="GridControl\NewCellTypes\GridCellDateTime.h" />
+ <ClInclude Include="GridControl\NewCellTypes\GridCellNumeric.h" />
+ <ClInclude Include="GridControl\NewCellTypes\GridURLCell.h" />
+ <ClInclude Include="GridControl\TitleTip.h" />
<ClInclude Include="JobSlotGrid.h" />
<ClInclude Include="MsgDlg.h" />
<ClInclude Include="PageRecipe.h" />
@@ -290,6 +304,7 @@
<ClInclude Include="MapPosWnd.h" />
<ClInclude Include="Model.h" />
<ClInclude Include="PageRobotCmd.h" />
+ <ClInclude Include="PortConfigurationDlg.h" />
<ClInclude Include="ProductionLogManager.h" />
<ClInclude Include="Resource.h" />
<ClInclude Include="SECSRuntimeManager.h" />
@@ -302,6 +317,7 @@
<ClInclude Include="targetver.h" />
<ClInclude Include="TerminalDisplayDlg.h" />
<ClInclude Include="ToolUnits.h" />
+ <ClInclude Include="TransferManager.h" />
<ClInclude Include="VerticalLine.h" />
</ItemGroup>
<ItemGroup>
@@ -311,6 +327,18 @@
<ClCompile Include="CRobotCmdTestDlg.cpp" />
<ClCompile Include="CPagePortStatus.cpp" />
<ClCompile Include="CPortStatusReport.cpp" />
+ <ClCompile Include="GridControl\GridCell.cpp" />
+ <ClCompile Include="GridControl\GridCellBase.cpp" />
+ <ClCompile Include="GridControl\GridCellButton.cpp" />
+ <ClCompile Include="GridControl\GridCtrl.cpp" />
+ <ClCompile Include="GridControl\GridDropTarget.cpp" />
+ <ClCompile Include="GridControl\GridInPlaceEdit.cpp" />
+ <ClCompile Include="GridControl\NewCellTypes\GridCellCheck.cpp" />
+ <ClCompile Include="GridControl\NewCellTypes\GridCellCombo.cpp" />
+ <ClCompile Include="GridControl\NewCellTypes\GridCellDateTime.cpp" />
+ <ClCompile Include="GridControl\NewCellTypes\GridCellNumeric.cpp" />
+ <ClCompile Include="GridControl\NewCellTypes\GridURLCell.cpp" />
+ <ClCompile Include="GridControl\TitleTip.cpp" />
<ClCompile Include="JobSlotGrid.cpp" />
<ClCompile Include="MsgDlg.cpp" />
<ClCompile Include="PageRecipe.cpp" />
@@ -396,6 +424,7 @@
<ClCompile Include="MapPosWnd.cpp" />
<ClCompile Include="Model.cpp" />
<ClCompile Include="PageRobotCmd.cpp" />
+ <ClCompile Include="PortConfigurationDlg.cpp" />
<ClCompile Include="ProductionLogManager.cpp" />
<ClCompile Include="SECSRuntimeManager.cpp" />
<ClCompile Include="SecsTestDlg.cpp" />
@@ -410,6 +439,7 @@
</ClCompile>
<ClCompile Include="TerminalDisplayDlg.cpp" />
<ClCompile Include="ToolUnits.cpp" />
+ <ClCompile Include="TransferManager.cpp" />
<ClCompile Include="VerticalLine.cpp" />
</ItemGroup>
<ItemGroup>
diff --git a/SourceCode/Bond/Servo/Servo.vcxproj.filters b/SourceCode/Bond/Servo/Servo.vcxproj.filters
index 68273f0..1a8bb3f 100644
--- a/SourceCode/Bond/Servo/Servo.vcxproj.filters
+++ b/SourceCode/Bond/Servo/Servo.vcxproj.filters
@@ -112,6 +112,44 @@
<ClCompile Include="MsgDlg.cpp" />
<ClCompile Include="CPagePortStatus.cpp" />
<ClCompile Include="JobSlotGrid.cpp" />
+ <ClCompile Include="GridControl\GridCell.cpp">
+ <Filter>GridControl</Filter>
+ </ClCompile>
+ <ClCompile Include="GridControl\GridCellBase.cpp">
+ <Filter>GridControl</Filter>
+ </ClCompile>
+ <ClCompile Include="GridControl\GridCellButton.cpp">
+ <Filter>GridControl</Filter>
+ </ClCompile>
+ <ClCompile Include="GridControl\GridCtrl.cpp">
+ <Filter>GridControl</Filter>
+ </ClCompile>
+ <ClCompile Include="GridControl\GridDropTarget.cpp">
+ <Filter>GridControl</Filter>
+ </ClCompile>
+ <ClCompile Include="GridControl\GridInPlaceEdit.cpp">
+ <Filter>GridControl</Filter>
+ </ClCompile>
+ <ClCompile Include="GridControl\TitleTip.cpp">
+ <Filter>GridControl</Filter>
+ </ClCompile>
+ <ClCompile Include="GridControl\NewCellTypes\GridCellCheck.cpp">
+ <Filter>GridControl\NewCellTypes</Filter>
+ </ClCompile>
+ <ClCompile Include="GridControl\NewCellTypes\GridCellCombo.cpp">
+ <Filter>GridControl\NewCellTypes</Filter>
+ </ClCompile>
+ <ClCompile Include="GridControl\NewCellTypes\GridCellDateTime.cpp">
+ <Filter>GridControl\NewCellTypes</Filter>
+ </ClCompile>
+ <ClCompile Include="GridControl\NewCellTypes\GridCellNumeric.cpp">
+ <Filter>GridControl\NewCellTypes</Filter>
+ </ClCompile>
+ <ClCompile Include="GridControl\NewCellTypes\GridURLCell.cpp">
+ <Filter>GridControl\NewCellTypes</Filter>
+ </ClCompile>
+ <ClCompile Include="PortConfigurationDlg.cpp" />
+ <ClCompile Include="TransferManager.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="AlarmManager.h" />
@@ -223,6 +261,50 @@
<ClInclude Include="CPagePortStatus.h" />
<ClInclude Include="ServoCommo.h" />
<ClInclude Include="JobSlotGrid.h" />
+ <ClInclude Include="GridControl\CellRange.h">
+ <Filter>GridControl</Filter>
+ </ClInclude>
+ <ClInclude Include="GridControl\GridCell.h">
+ <Filter>GridControl</Filter>
+ </ClInclude>
+ <ClInclude Include="GridControl\GridCellBase.h">
+ <Filter>GridControl</Filter>
+ </ClInclude>
+ <ClInclude Include="GridControl\GridCellButton.h">
+ <Filter>GridControl</Filter>
+ </ClInclude>
+ <ClInclude Include="GridControl\GridCtrl.h">
+ <Filter>GridControl</Filter>
+ </ClInclude>
+ <ClInclude Include="GridControl\GridDropTarget.h">
+ <Filter>GridControl</Filter>
+ </ClInclude>
+ <ClInclude Include="GridControl\GridInPlaceEdit.h">
+ <Filter>GridControl</Filter>
+ </ClInclude>
+ <ClInclude Include="GridControl\GridMemDC.h">
+ <Filter>GridControl</Filter>
+ </ClInclude>
+ <ClInclude Include="GridControl\TitleTip.h">
+ <Filter>GridControl</Filter>
+ </ClInclude>
+ <ClInclude Include="GridControl\NewCellTypes\GridCellCheck.h">
+ <Filter>GridControl\NewCellTypes</Filter>
+ </ClInclude>
+ <ClInclude Include="GridControl\NewCellTypes\GridCellCombo.h">
+ <Filter>GridControl\NewCellTypes</Filter>
+ </ClInclude>
+ <ClInclude Include="GridControl\NewCellTypes\GridCellDateTime.h">
+ <Filter>GridControl\NewCellTypes</Filter>
+ </ClInclude>
+ <ClInclude Include="GridControl\NewCellTypes\GridCellNumeric.h">
+ <Filter>GridControl\NewCellTypes</Filter>
+ </ClInclude>
+ <ClInclude Include="GridControl\NewCellTypes\GridURLCell.h">
+ <Filter>GridControl\NewCellTypes</Filter>
+ </ClInclude>
+ <ClInclude Include="PortConfigurationDlg.h" />
+ <ClInclude Include="TransferManager.h" />
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="Servo.rc" />
@@ -241,5 +323,11 @@
<Filter Include="CCLinkPerformance">
<UniqueIdentifier>{77338295-9841-4706-8816-a958b1b5c465}</UniqueIdentifier>
</Filter>
+ <Filter Include="GridControl">
+ <UniqueIdentifier>{1206b229-6054-40f2-8d8a-5848582a3896}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="GridControl\NewCellTypes">
+ <UniqueIdentifier>{52ebd40d-fb71-4a53-93ab-5b93670c706d}</UniqueIdentifier>
+ </Filter>
</ItemGroup>
</Project>
\ No newline at end of file
diff --git a/SourceCode/Bond/Servo/Servo.vcxproj.user b/SourceCode/Bond/Servo/Servo.vcxproj.user
index 405156d..0c03257 100644
--- a/SourceCode/Bond/Servo/Servo.vcxproj.user
+++ b/SourceCode/Bond/Servo/Servo.vcxproj.user
@@ -4,8 +4,8 @@
<RESOURCE_FILE>Servo.rc</RESOURCE_FILE>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
- <RemoteDebuggerCommand>D:\Servo\Debug\Servo.exe</RemoteDebuggerCommand>
- <RemoteDebuggerWorkingDirectory>D:\Servo\Debug\</RemoteDebuggerWorkingDirectory>
+ <RemoteDebuggerCommand>\\DESKTOP-IODBVIQ\Servo\Debug\Servo.exe</RemoteDebuggerCommand>
+ <RemoteDebuggerWorkingDirectory>\\DESKTOP-IODBVIQ\Servo\Debug\</RemoteDebuggerWorkingDirectory>
<RemoteDebuggerServerName>DESKTOP-IODBVIQ</RemoteDebuggerServerName>
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
</PropertyGroup>
diff --git a/SourceCode/Bond/Servo/TransferManager.cpp b/SourceCode/Bond/Servo/TransferManager.cpp
new file mode 100644
index 0000000..bfcf457
--- /dev/null
+++ b/SourceCode/Bond/Servo/TransferManager.cpp
@@ -0,0 +1,550 @@
+#include "stdafx.h"
+#include "TransferManager.h"
+#include <iostream>
+#include <sstream>
+#include <fstream>
+#include <iomanip>
+#include <ctime>
+#include <stdexcept>
+
+// 静态互斥锁初始化
+std::mutex TransferManager::m_mutex;
+
+// 获取 TransferManager 单例
+TransferManager& TransferManager::getInstance() {
+ static TransferManager instance;
+ return instance;
+}
+
+// 构造函数
+TransferManager::TransferManager() {
+ m_pDB = new BL::SQLiteDatabase();
+}
+
+// 析构函数
+TransferManager::~TransferManager() {
+ if (m_pDB) {
+ delete m_pDB;
+ m_pDB = nullptr;
+ }
+}
+
+// 任务状态转换成 int 类型
+int TransferManager::statusToInt(TransferStatus status) {
+ return static_cast<int>(status);
+}
+
+// int 类型转换成任务状态
+TransferStatus TransferManager::intToStatus(int value) {
+ switch (value) {
+ case 0: return TransferStatus::Ready;
+ case 1: return TransferStatus::Running;
+ case 2: return TransferStatus::Error;
+ case 3: return TransferStatus::Abort;
+ case 4: return TransferStatus::Completed;
+ default: return TransferStatus::Error;
+ }
+}
+
+// 任务状态转换成字符串
+std::string TransferManager::statusToString(TransferStatus status) {
+ switch (status) {
+ case TransferStatus::Ready: return "Ready";
+ case TransferStatus::Running: return "Running";
+ case TransferStatus::Error: return "Error";
+ case TransferStatus::Abort: return "Abort";
+ case TransferStatus::Completed: return "Completed";
+ default: return "Unknown";
+ }
+}
+
+// 字符串转换成任务状态
+TransferStatus TransferManager::stringToStatus(const std::string& str) {
+ if (str == "Ready") return TransferStatus::Ready;
+ if (str == "Running") return TransferStatus::Running;
+ if (str == "Error") return TransferStatus::Error;
+ if (str == "Abort") return TransferStatus::Abort;
+ if (str == "Completed") return TransferStatus::Completed;
+ return TransferStatus::Error;
+}
+
+// 本地编码转为 UTF-8
+std::string TransferManager::ansiToUtf8(const std::string& ansiStr) {
+ // 1. ANSI → UTF-16
+ int wideLen = MultiByteToWideChar(CP_ACP, 0, ansiStr.c_str(), -1, nullptr, 0);
+ std::wstring wideStr(wideLen, 0);
+ MultiByteToWideChar(CP_ACP, 0, ansiStr.c_str(), -1, &wideStr[0], wideLen);
+
+ // 2. UTF-16 → UTF-8
+ int utf8Len = WideCharToMultiByte(CP_UTF8, 0, wideStr.c_str(), -1, nullptr, 0, nullptr, nullptr);
+ std::string utf8Str(utf8Len, 0);
+ WideCharToMultiByte(CP_UTF8, 0, wideStr.c_str(), -1, &utf8Str[0], utf8Len, nullptr, nullptr);
+
+ utf8Str.pop_back(); // 去掉最后的 '\0'
+ return utf8Str;
+}
+
+// UTF-8 转为本地编码
+std::string TransferManager::utf8ToAnsi(const std::string& utf8Str) {
+ // 1. UTF-8 → UTF-16
+ int wideLen = MultiByteToWideChar(CP_UTF8, 0, utf8Str.c_str(), -1, NULL, 0);
+ std::wstring wideStr(wideLen, 0);
+ MultiByteToWideChar(CP_UTF8, 0, utf8Str.c_str(), -1, &wideStr[0], wideLen);
+
+ // 2. UTF-16 → ANSI
+ int ansiLen = WideCharToMultiByte(CP_ACP, 0, wideStr.c_str(), -1, NULL, 0, NULL, NULL);
+ std::string ansiStr(ansiLen, 0);
+ WideCharToMultiByte(CP_ACP, 0, wideStr.c_str(), -1, &ansiStr[0], ansiLen, NULL, NULL);
+
+ ansiStr.pop_back(); // 去掉最后的 '\0'
+ return ansiStr;
+}
+
+// 初始化搬运记录表
+bool TransferManager::initTransferTable() {
+ char szPath[MAX_PATH];
+ GetModuleFileName(NULL, szPath, MAX_PATH);
+ std::string exePath(szPath);
+ std::string dbDir = exePath.substr(0, exePath.find_last_of("\\/")) + "\\DB";
+
+ if (!CreateDirectory(dbDir.c_str(), NULL) && GetLastError() != ERROR_ALREADY_EXISTS) {
+ throw std::runtime_error("创建数据库目录失败");
+ }
+
+ std::string dbPath = dbDir + "\\TransferManager.db";
+
+ if (!m_pDB->connect(dbPath, true)) {
+ throw std::runtime_error("连接数据库失败");
+ }
+
+ const std::string createTableSQL = R"(
+ CREATE TABLE IF NOT EXISTS transfers (
+ record_id INTEGER PRIMARY KEY AUTOINCREMENT,
+ class_id TEXT NOT NULL,
+ status TEXT NOT NULL,
+ create_time TEXT,
+ pick_time TEXT,
+ place_time TEXT,
+ end_time TEXT,
+ description TEXT
+ );
+ )";
+
+ return m_pDB->executeQuery(createTableSQL);
+}
+
+// 插入测试搬运记录
+void TransferManager::insertTestTransferRecord() {
+ TransferData data;
+ data.strClassID = "Task-20240529-001";
+ data.strStatus = "Running";
+ data.strCreateTime = "2024-05-29 10:30:00";
+ data.strPickTime = "2024-05-29 10:31:00";
+ data.strPlaceTime = "2024-05-29 10:32:00";
+ data.strEndTime = "2024-05-29 10:33:00";
+ data.strDescription = "搬运动作:从 Port1 取片 → Port2 放片";
+
+ int nRecordId = -1;
+ if (TransferManager::getInstance().addTransferRecord(data, nRecordId)) {
+ std::cout << "插入成功,记录 ID = " << nRecordId << std::endl;
+ }
+ else {
+ std::cerr << "插入失败!" << std::endl;
+ }
+}
+
+// 断开数据库连接
+void TransferManager::termTransferTable() {
+ if (m_pDB) {
+ m_pDB->disconnect();
+ }
+}
+
+// 删除搬运记录表
+bool TransferManager::destroyTransferTable() {
+ if (!m_pDB) return false;
+
+ const std::string dropTableSQL = "DROP TABLE IF EXISTS transfers;";
+ return m_pDB->executeQuery(dropTableSQL);
+}
+
+// 插入搬运记录
+bool TransferManager::addTransferRecord(const TransferData& data, int& outRecordId) {
+ if (!m_pDB) {
+ return false;
+ }
+
+ std::ostringstream oss;
+ oss << "INSERT INTO transfers (class_id, status, create_time, pick_time, place_time, end_time, description) "
+ << "VALUES ('"
+ << ansiToUtf8(data.strClassID) << "', '"
+ << ansiToUtf8(data.strStatus) << "', '"
+ << data.strCreateTime << "', '"
+ << data.strPickTime << "', '"
+ << data.strPlaceTime << "', '"
+ << data.strEndTime << "', '"
+ << ansiToUtf8(data.strDescription) << "') RETURNING record_id;";
+
+ std::lock_guard<std::mutex> lock(m_mutex);
+
+ auto results = m_pDB->fetchResults(oss.str());
+ if (!results.empty() && !results[0].empty()) {
+ try {
+ outRecordId = std::stoi(results[0][0]);
+ return true;
+ }
+ catch (const std::exception& e) {
+ std::cerr << "解析 record_id 出错: " << e.what() << std::endl;
+ }
+ }
+
+ return false;
+}
+
+// 查询所有搬运记录
+std::vector<TransferData> TransferManager::getAllTransfers() {
+ std::vector<TransferData> records;
+
+ if (!m_pDB) {
+ return records;
+ }
+
+ const std::string query = R"(
+ SELECT record_id, class_id, status, create_time, pick_time, place_time, end_time, description
+ FROM transfers
+ ORDER BY record_id DESC
+ )";
+
+ auto results = m_pDB->fetchResults(query);
+ for (const auto& row : results) {
+ if (row.size() != 8) continue;
+
+ TransferData data;
+ data.nRecordId = std::stoi(row[0]);
+ data.strClassID = row[1];
+ data.strStatus = row[2];
+ data.strCreateTime = row[3];
+ data.strPickTime = row[4];
+ data.strPlaceTime = row[5];
+ data.strEndTime = row[6];
+ data.strDescription = row[7];
+
+ records.push_back(data);
+ }
+
+ return records;
+}
+
+// 根据 ID 查询搬运记录
+TransferData TransferManager::getTransferById(int id) {
+ TransferData data;
+ if (!m_pDB) {
+ return data;
+ }
+ std::ostringstream oss;
+ oss << "SELECT record_id, class_id, status, create_time, pick_time, place_time, end_time, description "
+ << "FROM transfers WHERE record_id = " << id;
+ auto results = m_pDB->fetchResults(oss.str());
+ if (!results.empty() && results[0].size() == 8) {
+ data.nRecordId = std::stoi(results[0][0]);
+ data.strClassID = results[0][1];
+ data.strStatus = results[0][2];
+ data.strCreateTime = results[0][3];
+ data.strPickTime = results[0][4];
+ data.strPlaceTime = results[0][5];
+ data.strEndTime = results[0][6];
+ data.strDescription = results[0][7];
+ }
+ return data;
+}
+
+// 根据时间范围查询搬运记录
+std::vector<TransferData> TransferManager::getTransfersByTimeRange(const std::string& startTime, const std::string& endTime) {
+ std::vector<TransferData> records;
+ if (!m_pDB) {
+ return records;
+ }
+ std::ostringstream oss;
+ oss << "SELECT record_id, class_id, status, create_time, pick_time, place_time, end_time, description "
+ << "FROM transfers WHERE 1=1";
+ if (!startTime.empty()) {
+ oss << " AND create_time >= '" << startTime << "'";
+ }
+ if (!endTime.empty()) {
+ oss << " AND end_time <= '" << endTime << "'";
+ }
+ auto results = m_pDB->fetchResults(oss.str());
+ for (const auto& row : results) {
+ if (row.size() != 8) continue;
+ TransferData data;
+ data.nRecordId = std::stoi(row[0]);
+ data.strClassID = row[1];
+ data.strStatus = row[2];
+ data.strCreateTime = row[3];
+ data.strPickTime = row[4];
+ data.strPlaceTime = row[5];
+ data.strEndTime = row[6];
+ data.strDescription = row[7];
+ records.push_back(data);
+ }
+ return records;
+}
+
+// 查询指定状态的搬运记录
+std::vector<TransferData> TransferManager::getTransfersByStatus(const std::string& status) {
+ std::vector<TransferData> records;
+ if (!m_pDB) {
+ return records;
+ }
+
+ std::ostringstream oss;
+ oss << "SELECT record_id, class_id, status, create_time, pick_time, place_time, end_time, description "
+ << "FROM transfers WHERE status = '" << status << "' "
+ << "ORDER BY create_time DESC";
+
+ auto results = m_pDB->fetchResults(oss.str());
+ for (const auto& row : results) {
+ if (row.size() != 8) continue;
+
+ TransferData data;
+ data.nRecordId = std::stoi(row[0]);
+ data.strClassID = row[1];
+ data.strStatus = row[2];
+ data.strCreateTime = row[3];
+ data.strPickTime = row[4];
+ data.strPlaceTime = row[5];
+ data.strEndTime = row[6];
+ data.strDescription = row[7];
+
+ records.push_back(data);
+ }
+
+ return records;
+}
+
+// 分页获取搬运记录
+//std::vector<TransferData> TransferManager::getTransfers(int startPosition, int count) {
+// std::vector<TransferData> records;
+// if (!m_pDB) {
+// return records;
+// }
+// std::ostringstream oss;
+// oss << "SELECT record_id, class_id, status, create_time, pick_time, place_time, end_time, description "
+// << "FROM transfers ORDER BY create_time DESC LIMIT " << count << " OFFSET " << startPosition;
+// auto results = m_pDB->fetchResults(oss.str());
+// for (const auto& row : results) {
+// if (row.size() != 8) continue;
+// TransferData data;
+// data.nRecordId = std::stoi(row[0]);
+// data.strClassID = row[1];
+// data.strStatus = row[2];
+// data.strCreateTime = row[3];
+// data.strPickTime = row[4];
+// data.strPlaceTime = row[5];
+// data.strEndTime = row[6];
+// data.strDescription = row[7];
+// records.push_back(data);
+// }
+// return records;
+//}
+
+// 获取符合条件的记录总数
+int TransferManager::getTotalTransferCount() {
+ if (!m_pDB) {
+ return 0;
+ }
+
+ const std::string query = "SELECT COUNT(*) FROM transfers;";
+ auto results = m_pDB->fetchResults(query);
+
+ if (!results.empty() && !results[0].empty()) {
+ try {
+ return std::stoi(results[0][0]);
+ }
+ catch (const std::exception& e) {
+ std::cerr << "Error parsing total count: " << e.what() << std::endl;
+ }
+ }
+
+ return 0;
+}
+
+// 获取符合条件的记录总数
+int TransferManager::getTotalTransferCount(const TransferData& filter) {
+ if (!m_pDB) {
+ return 0;
+ }
+
+ std::ostringstream oss;
+ oss << "SELECT COUNT(*) FROM transfers WHERE 1=1";
+
+ // 状态筛选(完全匹配)
+ if (!filter.strStatus.empty()) {
+ oss << " AND status = '" << filter.strStatus << "'";
+ }
+
+ // 描述关键字模糊匹配
+ if (!filter.strDescription.empty()) {
+ oss << " AND description LIKE '%" << filter.strDescription << "%'";
+ }
+
+ // 时间范围筛选
+ if (!filter.strCreateTime.empty()) {
+ oss << " AND create_time >= '" << filter.strCreateTime << "'";
+ }
+ if (!filter.strEndTime.empty()) {
+ oss << " AND end_time <= '" << filter.strEndTime << "'";
+ }
+
+ auto results = m_pDB->fetchResults(oss.str());
+ if (!results.empty() && !results[0].empty()) {
+ try {
+ return std::stoi(results[0][0]);
+ }
+ catch (const std::exception& e) {
+ std::cerr << "Error parsing total count: " << e.what() << std::endl;
+ }
+ }
+
+ return 0;
+}
+
+std::vector<TransferData> TransferManager::getTransfers(const TransferData& filter, int pageNum, int pageSize) {
+ std::vector<TransferData> records;
+
+ if (!m_pDB) {
+ return records;
+ }
+
+ std::ostringstream oss;
+ oss << "SELECT record_id, class_id, status, create_time, pick_time, place_time, end_time, description "
+ << "FROM transfers WHERE 1=1";
+
+ // 条件拼接(与 getTotalTransferCount 保持一致)
+ if (!filter.strStatus.empty()) {
+ oss << " AND status = '" << filter.strStatus << "'";
+ }
+ if (!filter.strDescription.empty()) {
+ oss << " AND description LIKE '%" << filter.strDescription << "%'";
+ }
+ if (!filter.strCreateTime.empty()) {
+ oss << " AND create_time >= '" << filter.strCreateTime << "'";
+ }
+ if (!filter.strEndTime.empty()) {
+ oss << " AND end_time <= '" << filter.strEndTime << "'";
+ }
+
+ // 分页控制
+ int offset = (pageNum - 1) * pageSize;
+ oss << " ORDER BY create_time DESC";
+ oss << " LIMIT " << pageSize << " OFFSET " << offset;
+
+ // 查询
+ auto results = m_pDB->fetchResults(oss.str());
+ for (const auto& row : results) {
+ if (row.size() != 8) continue;
+
+ TransferData data;
+ data.nRecordId = std::stoi(row[0]);
+ data.strClassID = row[1];
+ data.strStatus = row[2];
+ data.strCreateTime = row[3];
+ data.strPickTime = row[4];
+ data.strPlaceTime = row[5];
+ data.strEndTime = row[6];
+ data.strDescription = row[7];
+
+ records.push_back(data);
+ }
+
+ return records;
+}
+
+// 清理早于某一时间的搬运记录
+void TransferManager::cleanOldTransfers(int daysToKeep) {
+ if (!m_pDB) {
+ return;
+ }
+ std::ostringstream oss;
+ oss << "DELETE FROM transfers WHERE create_time < datetime('now', '-" << daysToKeep << " days')";
+
+ m_pDB->executeQuery(oss.str());
+}
+
+// 读取搬运记录 CSV 文件
+bool TransferManager::readTransferFile(const std::string& filename) {
+ std::ifstream file(filename);
+ if (!file.is_open()) {
+ std::cerr << "无法打开文件: " << filename << std::endl;
+ return false;
+ }
+
+ std::string line;
+ bool firstLine = true;
+ int insertedCount = 0;
+
+ while (std::getline(file, line)) {
+ if (firstLine) {
+ firstLine = false;
+ continue;
+ }
+
+ std::stringstream ss(line);
+ std::string cell;
+ TransferData data;
+
+ try {
+ std::getline(ss, cell, ',');
+ data.nRecordId = std::stoi(cell);
+
+ std::getline(ss, data.strClassID, ',');
+ std::getline(ss, data.strStatus, ',');
+ std::getline(ss, data.strCreateTime, ',');
+ std::getline(ss, data.strPickTime, ',');
+ std::getline(ss, data.strPlaceTime, ',');
+ std::getline(ss, data.strEndTime, ',');
+ std::getline(ss, data.strDescription, ',');
+
+ int newId = -1;
+ if (addTransferRecord(data, newId)) {
+ ++insertedCount;
+ }
+ }
+ catch (const std::exception& e) {
+ std::cerr << "读取错误行: " << line << ",错误: " << e.what() << std::endl;
+ continue;
+ }
+ }
+
+ file.close();
+ std::cout << "成功导入记录数: " << insertedCount << std::endl;
+ return true;
+}
+
+// 保存搬运记录到 CSV 文件
+bool TransferManager::saveTransferFile(const std::string& filename) {
+ std::ofstream file(filename);
+ if (!file.is_open()) {
+ std::cerr << "无法写入文件: " << filename << std::endl;
+ return false;
+ }
+
+ // 写入标题
+ file << "RecordID,ClassID,Status,CreateTime,PickTime,PlaceTime,EndTime,Description\n";
+
+ auto records = getAllTransfers();
+ for (const auto& data : records) {
+ file << data.nRecordId << ","
+ << data.strClassID << ","
+ << data.strStatus << ","
+ << data.strCreateTime << ","
+ << data.strPickTime << ","
+ << data.strPlaceTime << ","
+ << data.strEndTime << ","
+ << data.strDescription << "\n";
+ }
+
+ file.close();
+ std::cout << "已导出 " << records.size() << " 条记录到: " << filename << std::endl;
+ return true;
+}
\ No newline at end of file
diff --git a/SourceCode/Bond/Servo/TransferManager.h b/SourceCode/Bond/Servo/TransferManager.h
new file mode 100644
index 0000000..ed1bbf6
--- /dev/null
+++ b/SourceCode/Bond/Servo/TransferManager.h
@@ -0,0 +1,171 @@
+#ifndef TRANSFER_MANAGER_H
+#define TRANSFER_MANAGER_H
+
+#include <string>
+#include <vector>
+#include <mutex>
+#include <unordered_map>
+#include "Database.h"
+
+/**
+ * 任务状态枚举类型
+ */
+enum class TransferStatus {
+ Ready = 0,
+ Running,
+ Error,
+ Abort,
+ Completed
+};
+
+/**
+ * 搬运记录结构体
+ */
+struct TransferData {
+ int nRecordId; // 主键
+ std::string strClassID; // 搬运任务 ClassID
+ std::string strStatus; // 任务状态(字符串:Ready、Running...)
+ std::string strCreateTime; // 创建时间
+ std::string strPickTime; // 取片时间
+ std::string strPlaceTime; // 放片时间
+ std::string strEndTime; // 结束时间
+ std::string strDescription; // 任务说明
+};
+
+using TransferDataMap = std::unordered_map<int, TransferData>;
+
+class TransferManager {
+public:
+ /**
+ * 获取 TransferManager 单例
+ * @return TransferManager 实例
+ */
+ static TransferManager& getInstance();
+
+ /**
+ * 初始化搬运记录表
+ * @return 成功返回 true,失败返回 false
+ */
+ bool initTransferTable();
+
+ /**
+ * 插入测试搬运记录
+ */
+ void insertTestTransferRecord();
+
+ /**
+ * 终止数据库连接
+ */
+ void termTransferTable();
+
+ /**
+ * 删除搬运记录表
+ * @return 成功返回 true,失败返回 false
+ */
+ bool destroyTransferTable();
+
+ /**
+ * 插入搬运记录
+ * @param data 搬运记录结构体
+ * @param outRecordId 插入后的记录主键 ID
+ * @return 成功返回 true,失败返回 false
+ */
+ bool addTransferRecord(const TransferData& data, int& outRecordId);
+
+ /**
+ * 查询所有搬运记录
+ * @return 所有记录数据
+ */
+ std::vector<TransferData> getAllTransfers();
+
+ /**
+ * 根据记录 ID 查询搬运记录
+ * @param id 记录主键 ID
+ * @return 搬运记录数据
+ */
+ TransferData getTransferById(int id);
+
+ /**
+ * 根据时间范围查询搬运记录
+ * @param startTime 起始时间
+ * @param endTime 结束时间
+ * @return 搬运记录数据
+ */
+ std::vector<TransferData> getTransfersByTimeRange(const std::string& startTime, const std::string& endTime);
+
+ /**
+ * 根据状态查询搬运记录
+ * @param status 任务状态
+ * @return 搬运记录数据
+ */
+ std::vector<TransferData> TransferManager::getTransfersByStatus(const std::string& status);
+
+ /**
+ * 分页获取搬运记录
+ * @param startPosition 起始记录位置
+ * @param count 获取的记录数量
+ * @return 搬运记录数据
+ */
+ //std::vector<TransferData> getTransfers(int startPosition, int count);
+
+ /**
+ * 获取符合条件的记录总数
+ */
+ int getTotalTransferCount();
+
+ /**
+ * 分页获取符合条件的搬运记录
+ * @param filter 过滤条件
+ * @param pageNum 页码
+ * @param pageSize 每页记录数
+ */
+ std::vector<TransferData> getTransfers(const TransferData& filter, int pageNum, int pageSize);
+
+ /**
+ * 获取符合条件的记录总数
+ * @param filter 过滤条件
+ * @return 符合条件的记录总数
+ */
+ int getTotalTransferCount(const TransferData& filter);;
+
+ /**
+ * 清理早于某一时间的搬运记录
+ * @param daysToKeep 保留的天数
+ */
+ void cleanOldTransfers(int daysToKeep = 30);
+
+ /**
+ * 读取搬运记录 CSV 文件
+ * @param filename 文件名
+ * @return 成功返回 true,失败返回 false
+ */
+ bool readTransferFile(const std::string& filename);
+
+ /**
+ * 保存搬运记录到 CSV 文件
+ * @param filename 文件名
+ * @return 成功返回 true,失败返回 false
+ */
+ bool saveTransferFile(const std::string& filename);
+
+private:
+ TransferManager();
+ ~TransferManager();
+
+ // 禁止拷贝和赋值
+ TransferManager(const TransferManager&) = delete;
+ TransferManager& operator=(const TransferManager&) = delete;
+
+ // 内联函数
+ inline int statusToInt(TransferStatus status);
+ inline TransferStatus intToStatus(int value);
+ inline std::string statusToString(TransferStatus status);
+ inline TransferStatus stringToStatus(const std::string& str);
+ inline std::string ansiToUtf8(const std::string& ansiStr);
+ inline std::string utf8ToAnsi(const std::string& utf8Str);
+
+ BL::Database* m_pDB;
+ static std::mutex m_mutex;
+};
+
+#endif // TRANSFER_MANAGER_H
\ No newline at end of file
diff --git a/SourceCode/Bond/Servo/resource.h b/SourceCode/Bond/Servo/resource.h
index 3b75c47..f530d52 100644
--- a/SourceCode/Bond/Servo/resource.h
+++ b/SourceCode/Bond/Servo/resource.h
Binary files differ
diff --git a/SourceCode/Bond/Servo/stdafx.h b/SourceCode/Bond/Servo/stdafx.h
index d63dafa..8e4739a 100644
--- a/SourceCode/Bond/Servo/stdafx.h
+++ b/SourceCode/Bond/Servo/stdafx.h
@@ -34,6 +34,17 @@
#include <afxcontrolbars.h> // 功能区和控件条的 MFC 支持
+// 控件样式
+static UINT g_nGridFixCellColor = RGB(144, 200, 246);
+static UINT g_nGridFixFontColor = RGB(0, 0, 0);
+static UINT g_nGridCellColor = RGB(255, 255, 224);
+static UINT g_nGridCellColor_NonSelect = RGB(150, 150, 150);
+static UINT g_nGridCellReadyColor = RGB(255, 255, 0);
+static UINT g_nGridCellOnColor = RGB(255, 69, 0);
+static UINT g_nGridCellOffColor = RGB(128, 191, 255);
+static UINT g_nPropertyGridFixCellColor = RGB(150, 150, 150);
+static UINT g_nPropertyGridFixFontColor = RGB(0, 0, 0);
+
// GDI+
#include <gdiplus.h>
using namespace Gdiplus;
--
Gitblit v1.9.3