- // GridCtrl.cpp : implementation file
- //
- // MFC Grid Control v2.20
- //
- // Written by Chris Maunder <cmaunder@mail.com>
- // Copyright (c) 1998-2000. All Rights Reserved.
- //
- // 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
- // (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.01 20 Feb 2000 - Eric Woodruff
- // Added better support for printing grids and
- // also fixed some other minor problems.
- //
- // 2.02 29 Feb 2000 - Brian V. Shifrin, Scot Reed,
- // Fixes to reduce flicker, fix font selection bug,
- // Fixed SetFixed[Row/Col]Count bug
- //
- // 2.03 28 Mar 2000 - Aqiruse (marked with //FNA)
- // Titletips now use cell color
- //
- // 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.11 19 May 2000 - Chris Maunder
- // - Increasing fixed cells clashed with selected cells (Ivan Ilinov)
- // - AutoSizeRows obvous bug fixed
- // - OnLButtonDown fix (Ken Bertelson)
- // - ExpandToFit bug fixed (scrollbar space) (Igor Proskuriakov)
- // - List mode selection/deselection fixed
- // - Keyboard cell movement improved. You can now see the cells!
- // - m_nBarState MS madness fixed (Phil K)
- //
- // 2.12 26 May 2000 - Martin Richter
- // - If using TRY/CATCH (winCE) instead of try/catch (win32),
- // e->Delete is not called
- // - EnsureVisible "fix" was fixed properly.
- //
- // 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
- //
- // 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
- // 4) Get some sleep
- //
- // ISSUES: 1) Crashes in the HPC/Pro emulation - but works fine on a device. ???
- //
- /////////////////////////////////////////////////////////////////////////////
- #include "stdafx.h"
- #include "MemDC.h"
- #include "GridCtrl.h"
- // OLE stuff for clipboard operations
- #include <afxadv.h> // For CSharedFile
- #include <afxconv.h> // For LPTSTR -> LPSTR macros
- #ifdef _DEBUG
- #define new DEBUG_NEW
- #undef THIS_FILE
- static 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;
- VersionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
- if (!GetVersionEx(&VersionInfo) ||
- (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;
- }
- /////////////////////////////////////////////////////////////////////////////
- // CGridCtrl
- CGridCtrl::CGridCtrl(int nRows, int nCols, int nFixedRows, int nFixedCols)
- {
- RegisterWindowClass();
- // Initialize OLE libraries
- m_bMustUninitOLE = FALSE;
- #if !defined(GRIDCONTROL_NO_DRAGDROP) || !defined(GRIDCONTROL_NO_CLIPBOARD)
- _AFX_THREAD_STATE* pState = AfxGetThreadState();
- if (!pState->m_bNeedTerm)
- {
- SCODE sc = ::OleInitialize(NULL);
- if (FAILED(sc))
- AfxMessageBox(_T("OLE initialization failed. Make sure that the OLE libraries are the correct version"));
- else
- m_bMustUninitOLE = TRUE;
- }
- #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_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_bMouseButtonDown = 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_nAutoSizeColumnStyle = GVS_BOTH; // Autosize grid using header and data info
- m_nTimerID = 0; // For drag-selection
- m_nTimerInterval = 25; // (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 = TRUE; // Track Focus cell?
- m_bFrameFocus = TRUE; // Frame the selected cell?
- m_pRtcDefault = RUNTIME_CLASS(CGridCell);
- SetupDefaultCells();
- SetGridBkColor(m_crShadow);
- // Set up the initial grid size
- SetRowCount(nRows);
- SetColumnCount(nCols);
- SetFixedRowCount(nFixedRows);
- SetFixedColumnCount(nFixedCols);
- 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
- }
- CGridCtrl::~CGridCtrl()
- {
- 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();
- // Uninitialize OLE support
- if (m_bMustUninitOLE)
- ::OleUninitialize();
- #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 | CS_HREDRAW | CS_VREDRAW;
- 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_DRAGDROP
- m_DropTarget.Register(this);
- #endif
- #ifndef GRIDCONTROL_NO_TITLETIPS
- m_TitleTip.SetParentWnd(this);
- #endif
- if (::IsWindow(m_hWnd))
- ModifyStyleEx(0, WS_EX_CLIENTEDGE, 0);
- 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();
- // 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
- for (int 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();
- ResetScrollBars(); //- called in OnSize anyway
- 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();
- // ResetScrollBars(); - called in OnSize anyway
- }
- // 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(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;
- }
- 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_NOTIFY(GVN_ENDLABELEDIT, IDC_INPLACE_CONTROL, OnEndInPlaceEdit)
- 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
- {
- CMemDC 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());
- //CBrush Back(GetTextBkColor());
- 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, VisRect.bottom),
- &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;
- // 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 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);
- int nFixedRowHeight = GetFixedRowHeight();
- int nFixedColWidth = GetFixedColumnWidth();
- 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;
- if (IsCTRLpressed())
- {
- switch (nChar)
- {
- case 'A':
- OnEditSelectAll();
- 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;
- switch (nChar)
- {
- case VK_DELETE:
- if (IsCellEditable(m_idCurrentCell.row, m_idCurrentCell.col))
- {
- SendMessageToParent(m_idCurrentCell.row, m_idCurrentCell.col, GVN_BEGINLABELEDIT);
- SetItemText(m_idCurrentCell.row, m_idCurrentCell.col, _T(""));
- SetModified(TRUE, m_idCurrentCell.row, m_idCurrentCell.col);
- SendMessageToParent(m_idCurrentCell.row, m_idCurrentCell.col, GVN_ENDLABELEDIT);
- RedrawCell(m_idCurrentCell);
- }
- break;
- case VK_TAB:
- if (IsSHIFTpressed())
- {
- if (next.col > m_nFixedCols)
- next.col--;
- else if (next.col == m_nFixedCols && next.row > m_nFixedRows)
- {
- next.row--;
- next.col = GetColumnCount() - 1;
- bChangeLine = TRUE;
- }
- else
- CWnd::OnKeyDown(nChar, nRepCnt, nFlags);
- }
- else
- {
- if (next.col <(GetColumnCount() - 1))
- next.col++;
- else if (next.col == (GetColumnCount() - 1) &&
- next.row <(GetRowCount() - 1))
- {
- next.row++;
- next.col = m_nFixedCols;
- bChangeLine = TRUE;
- }
- else
- CWnd::OnKeyDown(nChar, nRepCnt, nFlags);
- }
- break;
- case 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;
- break;
- case VK_UP:
- // don't let user go to a hidden row
- bFoundVisible = FALSE;
- iOrig = next.row;
- next.row--;
- while( next.row >= m_nFixedRows)
- {
- if( GetRowHeight( next.row) > 0)
- {
- bFoundVisible = TRUE;
- break;
- }
- next.row--;
- }
- if( !bFoundVisible)
- next.row = iOrig;
- break;
- case VK_RIGHT:
- // don't let user go to a hidden column
- bFoundVisible = FALSE;
- iOrig = next.col;
- next.col++;
- while( next.col < GetColumnCount())
- {
- if( GetColumnWidth( next.col) > 0)
- {
- bFoundVisible = TRUE;
- break;
- }
- next.col++;
- }
- if( !bFoundVisible)
- next.col = iOrig;
- break;
- case VK_LEFT:
- // don't let user go to a hidden column
- bFoundVisible = FALSE;
- iOrig = next.col;
- next.col--;
- while( next.col >= m_nFixedCols)
- {
- if( GetColumnWidth( next.col) > 0)
- {
- bFoundVisible = TRUE;
- break;
- }
- next.col--;
- }
- if( !bFoundVisible)
- next.col = iOrig;
- break;
- case VK_NEXT:
- {
- CCellID idOldTopLeft = GetTopleftNonFixedCell();
- SendMessage(WM_VSCROLL, SB_PAGEDOWN, 0);
- 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;
- break;
- }
- case VK_PRIOR:
- {
- CCellID idOldTopLeft = GetTopleftNonFixedCell();
- SendMessage(WM_VSCROLL, SB_PAGEUP, 0);
- CCellID idNewTopLeft = GetTopleftNonFixedCell();
- int increment = idNewTopLeft.row - idOldTopLeft.row;
- if (increment)
- {
- next.row += increment;
- if (next.row < m_nFixedRows)
- next.row = m_nFixedRows;
- }
- else
- next.row = m_nFixedRows;
- break;
- }
- case 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);
- next.row = m_nFixedRows;
- next.col = m_nFixedCols;
- }
- else
- {
- SendMessage(WM_HSCROLL, SB_LEFT, 0);
- next.col = m_nFixedCols;
- }
- // 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++;
- }
- break;
- case 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);
- next.row = GetRowCount() - 1;
- next.col = GetColumnCount() - 1;
- }
- else
- {
- SendMessage(WM_HSCROLL, SB_RIGHT, 0);
- next.col = GetColumnCount() - 1;
- }
- // adjust column to avoid hidden columns and rows
- while( next.col > m_nFixedCols + 1)
- {
- if( GetColumnWidth( next.col) > 0)
- break;
- next.col--;
- }
- while( next.row > m_nFixedRows + 1)
- {
- if( GetRowHeight( next.row) > 0)
- break;
- next.row--;
- }
- break;
- case VK_F2:
- OnEditCell(m_idCurrentCell.row, m_idCurrentCell.col, CPoint( -1, -1), VK_LBUTTON);
- break;
- default:
- CWnd::OnKeyDown(nChar, nRepCnt, nFlags);
- return;
- }
- if (next != m_idCurrentCell)
- {
- // 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;
- OnSelecting(next);
- m_MouseMode = MOUSE_NOTHING;
- }
- SetFocusCell(next);
- if (!IsCellVisible(next))
- {
- switch (nChar)
- {
- case VK_RIGHT:
- SendMessage(WM_HSCROLL, SB_LINERIGHT, 0);
- break;
- case VK_LEFT:
- SendMessage(WM_HSCROLL, SB_LINELEFT, 0);
- break;
- case VK_DOWN:
- SendMessage(WM_VSCROLL, SB_LINEDOWN, 0);
- break;
- case VK_UP:
- SendMessage(WM_VSCROLL, SB_LINEUP, 0);
- break;
- case VK_TAB:
- if (IsSHIFTpressed())
- {
- if (bChangeLine)
- {
- SendMessage(WM_VSCROLL, SB_LINEUP, 0);
- SetScrollPos32(SB_HORZ, m_nHScrollMax);
- break;
- }
- else
- SendMessage(WM_HSCROLL, SB_LINELEFT, 0);
- }
- else
- {
- if (bChangeLine)
- {
- SendMessage(WM_VSCROLL, SB_LINEDOWN, 0);
- SetScrollPos32(SB_HORZ, 0);
- break;
- }
- else
- SendMessage(WM_HSCROLL, SB_LINERIGHT, 0);
- }
- break;
- }
- EnsureVisible(next); // Make sure cell is visible
- Invalidate();
- }
- EnsureVisible(next); // Make sure cell is visible
- }
- }
- 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);
- }
- // 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));
- SendMessageToParent(pgvItem->row, pgvItem->col, GVN_ENDLABELEDIT);
- 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(pgvItem->lParam, 0, 0);
- OnEditCell(m_idCurrentCell.row, m_idCurrentCell.col, CPoint( -1, -1), pgvItem->lParam);
- }
- *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);
- 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
- rect.left = GetFixedColumnWidth();
- //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())
- {
- int iColToUse = idTopLeft.col-1;
- // may have contiguous hidden columns. Blow by them
- while( iColToUse > GetFixedColumnCount()
- && GetColumnWidth( iColToUse) < 1 )
- {
- iColToUse--;
- }
- int xScroll = GetColumnWidth(iColToUse);
- SetScrollPos32(SB_HORZ, max(0, scrollPos - xScroll));
- rect.left = GetFixedColumnWidth();
- //ScrollWindow(xScroll, 0, rect);
- //rect.right = rect.left + xScroll;
- InvalidateRect(rect);
- }
- break;
- case SB_PAGERIGHT:
- if (scrollPos < m_nHScrollMax)
- {
- rect.left = GetFixedColumnWidth();
- int offset = rect.Width();
- int pos = min(m_nHScrollMax, scrollPos + offset);
- SetScrollPos32(SB_HORZ, pos);
- rect.left = GetFixedColumnWidth();
- InvalidateRect(rect);
- }
- break;
- case SB_PAGELEFT:
- if (scrollPos > 0)
- {
- rect.left = GetFixedColumnWidth();
- int offset = -rect.Width();
- int pos = max(0, scrollPos + offset);
- SetScrollPos32(SB_HORZ, pos);
- rect.left = GetFixedColumnWidth();
- 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)
- {
- rect.left = GetFixedColumnWidth();
- 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);
- 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
- rect.top = GetFixedRowHeight();
- //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())
- {
- int iRowToUse = idTopLeft.row-1;
- // may have contiguous hidden rows. Blow by them
- while( iRowToUse > GetFixedRowCount()
- && GetRowHeight( iRowToUse) < 1 )
- {
- iRowToUse--;
- }
- int yScroll = GetRowHeight( iRowToUse);
- SetScrollPos32(SB_VERT, max(0, scrollPos - yScroll));
- rect.top = GetFixedRowHeight();
- //ScrollWindow(0, yScroll, rect);
- //rect.bottom = rect.top + yScroll;
- InvalidateRect(rect);
- }
- break;
- case SB_PAGEDOWN:
- if (scrollPos < m_nVScrollMax)
- {
- rect.top = GetFixedRowHeight();
- scrollPos = min(m_nVScrollMax, scrollPos + rect.Height());
- SetScrollPos32(SB_VERT, scrollPos);
- rect.top = GetFixedRowHeight();
- InvalidateRect(rect);
- }
- break;
- case SB_PAGEUP:
- if (scrollPos > 0)
- {
- rect.top = GetFixedRowHeight();
- int offset = -rect.Height();
- int pos = max(0, scrollPos + offset);
- SetScrollPos32(SB_VERT, pos);
- rect.top = GetFixedRowHeight();
- 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)
- {
- rect.top = GetFixedRowHeight();
- 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.
- CRect rect;
- int row, col;
- CGridCellBase* pCell;
- int nFixedRowHeight = GetFixedRowHeight();
- int nFixedColWidth = GetFixedColumnWidth();
- 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;
- for (row = 0; row < m_nFixedRows; row++)
- {
- rect.top = rect.bottom+1;
- rect.bottom = rect.top + GetRowHeight(row)-1;
- rect.right = -1;
- for (col = 0; col < m_nFixedCols; col++)
- {
- rect.left = rect.right+1;
- rect.right = rect.left + GetColumnWidth(col)-1;
- pCell = GetCell(row, col);
- if (pCell)
- 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++)
- {
- 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 < m_nFixedCols; col++)
- {
- 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->Draw(pDC, row, col, rect, FALSE);
- }
- }
- // draw fixed row cells 0..m_nFixedRows, m_nFixedCols..n
- rect.bottom = -1;
- for (row = 0; row < m_nFixedRows; row++)
- {
- 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++)
- {
- 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->Draw(pDC, row, col, rect, FALSE);
- }
- }
- // draw rest of non-fixed cells
- rect.bottom = nFixedRowHeight-1;
- for (row = minVisibleRow; row <= maxVisibleRow; row++)
- {
- 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++)
- {
- 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: %sn"), row, col, pCell->GetRuntimeClass()->m_lpszClassName);
- if (pCell)
- 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)
- {
- int x = nFixedColWidth;
- for (col = minVisibleCol; col <= maxVisibleCol; col++)
- {
- x += GetColumnWidth(col);
- pDC->MoveTo(x-1, nFixedRowHeight);
- pDC->LineTo(x-1, VisRect.bottom);
- }
- }
- // draw horizontal lines (drawn at bottom of each cell)
- if (m_nGridLines == GVL_BOTH || m_nGridLines == GVL_HORZ)
- {
- int y = nFixedRowHeight;
- for (row = minVisibleRow; row <= maxVisibleRow; row++)
- {
- y += GetRowHeight(row);
- pDC->MoveTo(nFixedColWidth, y-1);
- pDC->LineTo(VisRect.right, y-1);
- }
- }
- pDC->SelectStockObject(NULL_PEN);
- }
- ////////////////////////////////////////////////////////////////////////////////////////
- // 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 %sn"),
- // GetRuntimeClass()->m_lpszClassName, bAllowDraw? _T("TRUE") : _T("FALSE"));
- if (bAllowDraw && !m_bAllowDraw)
- {
- m_bAllowDraw = TRUE;
- Refresh();
- }
- 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;
- 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);
- 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())
- cell.row = GetFixedRowCount();
- if(cell.col != -1 && cell.col < GetFixedColumnCount())
- cell.col = GetFixedColumnCount();
- m_idCurrentCell = cell;
- if (IsValid(idPrev))
- {
- SendMessageToParent(idPrev.row, idPrev.col, GVN_SELCHANGING);
- 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);
- SendMessageToParent(m_idCurrentCell.row, m_idCurrentCell.col, GVN_SELCHANGED);
- // 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;
- CDC* pDC = NULL;
- if (bForceRepaint)
- pDC = GetDC();
- // EFW - Bug fix - Don't allow selection of fixed rows
- if(nMinRow >= 0 && nMinRow < GetFixedRowCount())
- nMinRow = GetFixedRowCount();
- if(nMaxRow >= 0 && nMaxRow < GetFixedRowCount())
- nMaxRow = GetFixedRowCount();
- if(nMinCol >= 0 && nMinCol < GetFixedColumnCount())
- nMinCol = GetFixedColumnCount();
- if(nMaxCol >= 0 && nMaxCol < GetFixedColumnCount())
- nMaxCol = GetFixedColumnCount();
- // If we are selecting cells, then first clear out the list of currently selected cells, then
- if (bSelectCells)
- {
- // Unselect all previously selected cells
- for (POSITION 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 (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, the 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);
- // 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++)
- {
- int nState = GetItemState(row, col);
- // Why is there no XOR operator in C??? We have bitwise XOR ^, but what about ^^??
- if ( (bSelectCells && (nState & GVIS_SELECTED)) ||
- (!bSelectCells && !(nState & GVIS_SELECTED)) )
- continue; // Already selected or deselected - ignore
- // Set the selected state. This will add/remove the cell to m_SelectedCellMap
- if (bSelectCells)
- SetItemState(row, col, nState | GVIS_SELECTED);
- else
- SetItemState(row, col, GetItemState(row, col) & ~GVIS_SELECTED);
- // 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;
- if (GetSingleRowSelection())
- SetSelectedRange(currentCell.row, GetFixedColumnCount(),
- currentCell.row, GetColumnCount()-1,
- bForceRedraw, bSelectCells);
- else
- SetSelectedRange(min(m_SelectionStartCell.row, currentCell.row),
- GetFixedColumnCount(),
- 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;
- if (row < m_nFixedRows || col < m_nFixedCols)
- 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));
- }
- #ifndef GRIDCONTROL_NO_CLIPBOARD
- ////////////////////////////////////////////////////////////////////////////////////////
- // Clipboard functions
- // Deletes the contents from the selected cells
- void CGridCtrl::CutSelectedText()
- {
- if (!IsEditable())
- return;
- // Clear contents of selected cells.
- for (POSITION pos = m_SelectedCellMap.GetStartPosition(); pos != NULL; )
- {
- DWORD key;
- CCellID cell;
- m_SelectedCellMap.GetNextAssoc(pos, key, (CCellID&)cell);
- if (!IsCellEditable(cell))
- continue;
- CGridCellBase* pCell = GetCell(cell.row, cell.col);
- if (pCell)
- {
- // don't clear hidden cells
- if( m_arRowHeights[ cell.row] > 0
- && m_arColWidths[cell.col] > 0 )
- {
- SendMessageToParent(cell.row, cell.col, GVN_BEGINLABELEDIT);
- pCell->SetText(_T(""));
- SetModified(TRUE, cell.row, cell.col);
- SendMessageToParent(cell.row, cell.col, GVN_ENDLABELEDIT);
- }
- }
- }
- Refresh();
- }
- // Copies text from the selected cells to the clipboard
- COleDataSource* CGridCtrl::CopyTextFromGrid()
- {
- USES_CONVERSION;
- CCellRange Selection = GetSelectedCellRange();
- if (!IsValid(Selection))
- return NULL;
- // 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("n");
- sf.Write(T2A(str.GetBuffer(1)), str.GetLength());
- str.ReleaseBuffer();
- }
- char c = ' ';
- sf.Write(&c, 1);
- DWORD dwLen = 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)
- {
- 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), ::GlobalSize(hmem));
- // CF_TEXT is ANSI text, so we need to allocate a char* buffer
- // to hold this.
- LPSTR szBuffer = new char[::GlobalSize(hmem)];
- if (!szBuffer)
- return FALSE;
- sf.Read(szBuffer, ::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
- 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);
- // Make blank entries a "space"
- if (strLine.IsEmpty() && nIndex >= 0)
- strLine = _T(" ");
- LPTSTR szLine = strLine.GetBuffer(1);
- // Break the current line into tokens (tab or comma delimited)
- LPTSTR pszCellText = _tcstok(szLine, _T("t,n"));
- // skip hidden rows
- int iRowVis = cell.row + nLine;
- while( iRowVis < GetRowCount())
- {
- if( GetRowHeight( iRowVis) > 0)
- break;
- nLine++;
- iRowVis++;
- }
- while (pszCellText != NULL)
- {
- // 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))
- {
- CString strCellText = pszCellText;
- strCellText.TrimLeft();
- strCellText.TrimRight();
- SendMessageToParent(TargetCell.row, TargetCell.col, GVN_BEGINLABELEDIT);
- SetItemText(TargetCell.row, TargetCell.col, strCellText);
- SetModified(TRUE, TargetCell.row, TargetCell.col);
- SendMessageToParent(TargetCell.row, TargetCell.col, GVN_ENDLABELEDIT);
- // Make sure cell is not selected to avoid data loss
- SetItemState(TargetCell.row, TargetCell.col,
- GetItemState(TargetCell.row, TargetCell.col) & ~GVIS_SELECTED);
- }
- pszCellText = _tcstok(NULL, _T("t,n"));
- nColumn++;
- }
- strLine.ReleaseBuffer();
- strLine = strNext;
- nLine++;
- } while (nIndex >= 0);
- strText.UnlockBuffer();
- Refresh();
- return TRUE;
- }
- #endif
- #ifndef GRIDCONTROL_NO_DRAGDROP
- // Start drag n drop
- void CGridCtrl::OnBeginDrag()
- {
- if (!m_bAllowDragAndDrop)
- return;
- COleDataSource* pSource = CopyTextFromGrid();
- if (pSource)
- {
- SendMessageToParent(GetSelectedCellRange().GetTopLeft().row,
- GetSelectedCellRange().GetTopLeft().col,
- GVN_BEGINDRAG);
- m_MouseMode = MOUSE_DRAGGING;
- 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)
- {
- // Any text data available for us?
- if (!m_bAllowDragAndDrop || !IsEditable() || !pDataObject->IsDataAvailable(CF_TEXT))
- return DROPEFFECT_NONE;
- // Find which cell we are over and drop-highlight it
- CCellID cell = GetCellFromPt(point, FALSE);
- // If not valid, set the previously drop-highlighted cell as no longer drop-highlighted
- if (!IsValid(cell))
- {
- OnDragLeave();
- m_LastDragOverCell = CCellID(-1,-1);
- return DROPEFFECT_NONE;
- }
- if (!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?
- if (!m_bAllowDragAndDrop || !pDataObject->IsDataAvailable(CF_TEXT))
- return DROPEFFECT_NONE;
- // Find which cell we are over and drop-highlight it
- m_LastDragOverCell = GetCellFromPt(point, FALSE);
- if (!IsValid(m_LastDragOverCell))
- return DROPEFFECT_NONE;
- if (!IsCellEditable(m_LastDragOverCell))
- return DROPEFFECT_NONE;
- 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 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 */)
- {
- if (!m_bAllowDragAndDrop || !IsCellEditable(m_LastDragOverCell))
- return FALSE;
- m_MouseMode = MOUSE_NOTHING;
- OnDragLeave();
- return PasteTextToGrid(m_LastDragOverCell, pDataObject);
- }
- #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;
- // Get the Focus cell, or if none, get the topleft (non-fixed) cell
- CCellID cell = GetFocusCell();
- if (!IsValid(cell))
- cell = GetTopleftNonFixedCell();
- if (!IsValid(cell))
- 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()
- {
- SelectAllCells();
- }
- #ifndef GRIDCONTROL_NO_CLIPBOARD
- void CGridCtrl::OnUpdateEditCopy(CCmdUI* pCmdUI)
- {
- CCellRange Selection = GetSelectedCellRange();
- pCmdUI->Enable(Selection.Count() && IsValid(Selection));
- }
- void CGridCtrl::OnUpdateEditCut(CCmdUI* pCmdUI)
- {
- 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
- CCellID CGridCtrl::GetCellFromPt(CPoint point, BOOL bAllowFixedCellCheck /*=TRUE*/)
- {
- CCellID cellID; // return value
- CCellID idTopLeft = GetTopleftNonFixedCell();
- if (!IsValid(idTopLeft))
- return cellID;
- // calculate column index
- int fixedColWidth = GetFixedColumnWidth();
- 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;
- for (int col = 0; col < m_nFixedCols; col++)
- {
- xpos += GetColumnWidth(col);
- if (xpos > point.x)
- break;
- }
- cellID.col = col;
- }
- else // in non-fixed col
- {
- int xpos = fixedColWidth;
- for (int col = idTopLeft.col; col < GetColumnCount(); col++)
- {
- xpos += GetColumnWidth(col);
- if (xpos > point.x)
- break;
- }
- if (col >= GetColumnCount())
- cellID.col = -1;
- else
- cellID.col = col;
- }
- // calculate row index
- int fixedRowHeight = GetFixedRowHeight();
- 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;
- for (int row = 0; row < m_nFixedRows; row++)
- {
- ypos += GetRowHeight(row);
- if (ypos > point.y)
- break;
- }
- cellID.row = row;
- }
- else
- {
- int ypos = fixedRowHeight;
- for (int row = idTopLeft.row; row < GetRowCount(); row++)
- {
- ypos += GetRowHeight(row);
- if (ypos > point.y)
- break;
- }
- if (row >= GetRowCount())
- cellID.row = -1;
- else
- cellID.row = row;
- }
- return cellID;
- }
- ////////////////////////////////////////////////////////////////////////////////
- // CGridCtrl cellrange functions
- // Gets the first non-fixed cell ID
- CCellID CGridCtrl::GetTopleftNonFixedCell()
- {
- // Used cached value if possible
- if (m_idTopLeftCell.IsValid())
- return m_idTopLeftCell;
- int nVertScroll = GetScrollPos(SB_VERT),
- nHorzScroll = GetScrollPos(SB_HORZ);
- m_idTopLeftCell.col = m_nFixedCols;
- int nRight = 0;
- while (nRight < nHorzScroll && m_idTopLeftCell.col < (GetColumnCount()-1))
- nRight += GetColumnWidth(m_idTopLeftCell.col++);
- m_idTopLeftCell.row = m_nFixedRows;
- int nTop = 0;
- while (nTop < nVertScroll && m_idTopLeftCell.row < (GetRowCount()-1))
- nTop += GetRowHeight(m_idTopLeftCell.row++);
- //TRACE2("TopLeft cell is row %d, col %dn",m_idTopLeftCell.row, m_idTopLeftCell.col);
- return m_idTopLeftCell;
- }
- // This gets even partially visible cells
- CCellRange CGridCtrl::GetVisibleNonFixedCellRange(LPRECT pRect /*=NULL*/)
- {
- CRect rect;
- GetClientRect(rect);
- CCellID idTopLeft = GetTopleftNonFixedCell();
- // calc bottom
- int bottom = GetFixedRowHeight();
- for (int 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 = GetFixedColumnWidth();
- for (i = idTopLeft.col; i < GetColumnCount(); 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, idTopLeft.col, maxVisibleRow, maxVisibleCol);
- }
- // used by ResetScrollBars() - This gets only fully visible cells
- CCellRange CGridCtrl::GetUnobstructedNonFixedCellRange()
- {
- CRect rect;
- GetClientRect(rect);
- CCellID idTopLeft = GetTopleftNonFixedCell();
- // calc bottom
- int bottom = GetFixedRowHeight();
- for (int 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))
- {
- CWnd::EnableScrollBarCtrl(SB_HORZ, bEnable);
- m_nBarState |= GVL_HORZ;
- }
- if (!IsVisibleVScroll() && (nBar == SB_VERT || nBar == SB_BOTH))
- {
- CWnd::EnableScrollBarCtrl(SB_VERT, bEnable);
- m_nBarState |= GVL_VERT;
- }
- }
- else
- {
- if ( IsVisibleHScroll() && (nBar == SB_HORZ || nBar == SB_BOTH))
- {
- CWnd::EnableScrollBarCtrl(SB_HORZ, bEnable);
- m_nBarState &= ~GVL_HORZ;
- }
- if ( IsVisibleVScroll() && (nBar == SB_VERT || nBar == SB_BOTH))
- {
- CWnd::EnableScrollBarCtrl(SB_VERT, bEnable);
- m_nBarState &= ~GVL_VERT;
- }
- }
- }
- // 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();
- rect.top += GetFixedRowHeight();
- if (rect.left >= rect.right || rect.top >= rect.bottom)
- {
- EnableScrollBarCtrl(SB_BOTH, FALSE);
- return;
- }
- CRect VisibleRect(GetFixedColumnWidth(), GetFixedRowHeight(), rect.right, rect.bottom);
- CRect VirtualRect(GetFixedColumnWidth(), GetFixedRowHeight(), 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 %dn"),
- // 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
- 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);
- //TRACE(_T("H scroll: %d, V Scroll %dn"), m_nHScrollMax, m_nVScrollMax);
- }
- ////////////////////////////////////////////////////////////////////////////////////
- // 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;
- if (nCol >= m_nFixedCols || nRow >= m_nFixedRows)
- idTopLeft = GetTopleftNonFixedCell();
- if ((nRow >= m_nFixedRows && nRow < idTopLeft.row) ||
- (nCol>= m_nFixedCols && nCol < idTopLeft.col))
- return FALSE;
- p->x = 0;
- if (nCol < m_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 < m_nFixedCols; i++)
- p->x += GetColumnWidth(i);
- for (i = idTopLeft.col; i < nCol; i++)
- p->x += GetColumnWidth(i);
- }
- p->y = 0;
- if (nRow < m_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 < m_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,%dn",
- // 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);
- }
- // 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++)
- {
- for (int 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
- {
- for (int i = 0; i < GetFixedRowCount(); i++)
- for (int j = nFixedCols; j < m_nFixedCols; j++)
- SetItemState(i, j, GetItemState(i, j) & ~GVIS_FIXEDCOL );
- for (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();
- }
- }
- 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 TRUE;
- }
- 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)
- {
- // initialized column widths