/libusbK/src/inf-wizard2/src/CGridListCtrlEx.cpp
C++ | 2001 lines | 1294 code | 212 blank | 495 comment | 307 complexity | 92c3679da46e50cbf16eea7677c9cb79 MD5 | raw file
Possible License(s): GPL-3.0, LGPL-3.0, LGPL-2.0
Large files files are truncated, but you can click here to view the full file
- //------------------------------------------------------------------------
- // Author: Rolf Kristensen
- // Source: http://www.codeproject.com/KB/list/CGridListCtrlEx.aspx
- // License: Free to use for all (New BSD License)
- //------------------------------------------------------------------------
-
- #include "stdafx.h"
- #include "CGridListCtrlEx.h"
-
- #include <shlwapi.h> // IsThemeEnabled
- #include <afxole.h> // COleDataSource
-
- #pragma warning(disable:4100) // unreferenced formal parameter
-
- #include "CGridColumnTraitText.h"
- #include "CGridRowTraitText.h"
- #include "ViewConfigSection.h"
-
- //------------------------------------------------------------------------
- //! @cond INTERNAL
- //------------------------------------------------------------------------
- template<class T>
- class COleDropTargetWnd : public COleDropTarget
- {
- T* m_pWnd;
- BOOL m_DragSource;
- BOOL m_DragDestination;
-
- public:
- COleDropTargetWnd()
- : m_pWnd(NULL)
- , m_DragSource(false)
- , m_DragDestination(false)
- {}
-
- BOOL Register(T* pWnd)
- {
- if (m_pWnd != NULL)
- {
- ASSERT(m_pWnd == pWnd);
- return TRUE; // Already registered
- }
-
- if (COleDropTarget::Register(pWnd) == FALSE)
- return FALSE;
-
- m_pWnd = pWnd;
- return TRUE;
- }
-
- BOOL IsDragSource() const
- {
- return m_DragSource;
- }
- BOOL IsDragDestination() const
- {
- return m_DragDestination;
- }
- void SetDragSource(BOOL value)
- {
- m_DragSource = value;
- m_DragDestination = false;
- }
-
- virtual DROPEFFECT OnDragEnter(CWnd* pWnd, COleDataObject* pDataObject, DWORD dwKeyState, CPoint point)
- {
- ASSERT(m_pWnd == pWnd && m_pWnd != NULL);
- m_DragDestination = true;
- return m_pWnd->OnDragEnter(pDataObject, dwKeyState, point);
- }
-
- virtual DROPEFFECT OnDragOver(CWnd* pWnd, COleDataObject* pDataObject, DWORD dwKeyState, CPoint point)
- {
- ASSERT(m_pWnd == pWnd && m_pWnd != NULL);
- return m_pWnd->OnDragOver(pDataObject, dwKeyState, point);
- }
-
- virtual void OnDragLeave(CWnd* pWnd)
- {
- ASSERT(m_pWnd == pWnd && m_pWnd != NULL);
- m_DragDestination = false;
- m_pWnd->OnDragLeave();
- }
-
- virtual BOOL OnDrop(CWnd* pWnd, COleDataObject* pDataObject, DROPEFFECT dropEffect, CPoint point)
- {
- ASSERT(m_pWnd == pWnd && m_pWnd != NULL);
- m_DragDestination = false;
- return m_pWnd->OnDrop(pDataObject, dropEffect, point);
- }
- };
-
- template<class T>
- class COleDataSourceWnd : public COleDataSource
- {
- COleDropTargetWnd<T>* m_pTarget;
-
- public:
- COleDataSourceWnd(COleDropTargetWnd<T>* pTarget)
- : m_pTarget(pTarget)
- {
- if (m_pTarget != NULL)
- m_pTarget->SetDragSource(true);
- }
-
- ~COleDataSourceWnd()
- {
- if (m_pTarget != NULL)
- m_pTarget->SetDragSource(false);
- }
- };
- //------------------------------------------------------------------------
- //! @endcond INTERNAL
- //------------------------------------------------------------------------
-
- BEGIN_MESSAGE_MAP(CGridListCtrlEx, CListCtrl)
- //{{AFX_MSG_MAP(CGridListCtrlEx)
- ON_NOTIFY_REFLECT_EX(LVN_BEGINLABELEDIT, OnBeginLabelEdit)
- ON_NOTIFY_REFLECT_EX(LVN_ENDLABELEDIT, OnEndLabelEdit)
- ON_NOTIFY_REFLECT_EX(LVN_GETDISPINFO, OnGetDispInfo) // Text Callback
- ON_MESSAGE(LVM_DELETECOLUMN, OnDeleteColumn)
- ON_MESSAGE(LVM_INSERTCOLUMN, OnInsertColumn)
- ON_MESSAGE(LVM_SETCOLUMNWIDTH, OnSetColumnWidth)
- ON_NOTIFY_REFLECT(NM_CUSTOMDRAW, OnCustomDraw)
- ON_NOTIFY_EX(HDN_BEGINTRACKA, 0, OnHeaderBeginResize)
- ON_NOTIFY_EX(HDN_BEGINTRACKW, 0, OnHeaderBeginResize)
- ON_NOTIFY_EX(HDN_ENDTRACKA, 0, OnHeaderEndResize)
- ON_NOTIFY_EX(HDN_ENDTRACKW, 0, OnHeaderEndResize)
- ON_NOTIFY_EX(HDN_ITEMCHANGINGA, 0, OnHeaderItemChanging)
- ON_NOTIFY_EX(HDN_ITEMCHANGINGW, 0, OnHeaderItemChanging)
- ON_NOTIFY_EX(HDN_BEGINDRAG, 0, OnHeaderBeginDrag)
- ON_NOTIFY_EX(HDN_ENDDRAG, 0, OnHeaderEndDrag)
- ON_NOTIFY_EX(HDN_DIVIDERDBLCLICKA, 0, OnHeaderDividerDblClick)
- ON_NOTIFY_EX(HDN_DIVIDERDBLCLICKW, 0, OnHeaderDividerDblClick)
- ON_NOTIFY_EX(TTN_NEEDTEXTA, 0, OnToolNeedText)
- ON_NOTIFY_EX(TTN_NEEDTEXTW, 0, OnToolNeedText)
- ON_NOTIFY_REFLECT_EX(LVN_COLUMNCLICK, OnHeaderClick) // Column Click
- ON_NOTIFY_REFLECT_EX(NM_CLICK, OnItemClick) // Cell Click
- ON_NOTIFY_REFLECT_EX(NM_DBLCLK, OnItemDblClick) // Cell Double Click
- ON_NOTIFY_REFLECT_EX(LVN_ODFINDITEM, OnOwnerDataFindItem) // Owner Data Find Item
- ON_NOTIFY_REFLECT_EX(LVN_BEGINDRAG, OnBeginDrag) // Begin Drag Dropb
- ON_WM_CONTEXTMENU() // OnContextMenu
- ON_WM_KEYDOWN() // OnKeyDown
- ON_WM_LBUTTONDOWN() // OnLButtonDown(UINT nFlags, CPoint point)
- ON_WM_RBUTTONDOWN() // OnRButtonDown(UINT nFlags, CPoint point)
- ON_WM_LBUTTONDBLCLK() // OnLButtonDblClk
- ON_WM_HSCROLL() // OnHScroll
- ON_WM_VSCROLL() // OnVScroll
- ON_WM_CHAR() // OnChar (Keyboard search)
- ON_WM_PAINT() // OnPaint
- ON_WM_CREATE() // OnCreate
- ON_WM_KILLFOCUS() // OnKillFocus
- ON_WM_DESTROY() // OnDestroy
- ON_MESSAGE(WM_COPY, OnCopy) // Clipboard
- ON_MESSAGE(WM_SETFONT, OnSetFont) // SetFont notification
- //}}AFX_MSG_MAP
- END_MESSAGE_MAP()
-
- //------------------------------------------------------------------------
- //! Constructor
- //------------------------------------------------------------------------
- CGridListCtrlEx::CGridListCtrlEx()
- : m_FocusCell(-1)
- , m_SortCol(-1)
- , m_Ascending(false)
- , m_UsingVisualStyle(false)
- , m_pEditor(NULL)
- , m_LastSearchCell(-1)
- , m_LastSearchRow(-1)
- , m_RepeatSearchCount(0)
- , m_EmptyMarkupText(_T("There are no items to show in this view."))
- , m_pOleDropTarget(NULL)
- , m_Margin(1.0) // Higher row-height (more room for edit-ctrl border)
- , m_pDefaultRowTrait(new CGridRowTraitText)
- , m_pColumnConfig(NULL)
- , m_InvalidateMarkupText(true)
- , m_bUseVisualStyles(TRUE)
- {}
-
- //------------------------------------------------------------------------
- //! Destructor
- //------------------------------------------------------------------------
- CGridListCtrlEx::~CGridListCtrlEx()
- {
- for(int nCol = GetColumnTraitSize() - 1; nCol >= 0 ; --nCol)
- DeleteColumnTrait(nCol);
-
- delete m_pDefaultRowTrait;
- m_pDefaultRowTrait = NULL;
-
- delete m_pColumnConfig;
- m_pColumnConfig = NULL;
-
- if (m_pOleDropTarget) delete m_pOleDropTarget;
- m_pOleDropTarget = NULL;
- }
-
- //------------------------------------------------------------------------
- //! Sets the interface for handling state persistence for the list control
- //!
- //! @param pColumnConfig The new column state interface handler
- //------------------------------------------------------------------------
- void CGridListCtrlEx::SetupColumnConfig(CViewConfigSectionProfiles* pColumnConfig)
- {
- delete m_pColumnConfig;
- m_pColumnConfig = pColumnConfig;
-
- if (!m_pColumnConfig->HasDefaultConfig())
- {
- // Validate that column data is setup correctly
- CSimpleMap<int, int> uniqueChecker;
- for(int nCol = 0; nCol < GetColumnCount(); ++nCol)
- {
- if (IsColumnAlwaysHidden(nCol))
- continue;
- int nColData = GetColumnData(nCol);
- ASSERT(uniqueChecker.FindKey(nColData) == -1);
- uniqueChecker.Add(nColData, nCol);
- }
-
- SaveState(m_pColumnConfig->GetDefaultConfig());
- }
-
- LoadState(*m_pColumnConfig);
- }
-
- //------------------------------------------------------------------------
- //! Loads and applies the column configuration for the list control
- //!
- //! @param config The interface for persisting the configuration
- //------------------------------------------------------------------------
- void CGridListCtrlEx::LoadState(CViewConfigSection& config)
- {
- // Prevent updating the internal column-state-container while loading
- CViewConfigSectionProfiles* pColumnConfig = m_pColumnConfig;
- m_pColumnConfig = NULL;
-
- int nVisibleCols = config.GetIntSetting(_T("ColumnCount"));
-
- int nColCount = GetColumnCount();
- int* pOrderArray = new int[nColCount];
- GetColumnOrderArray(pOrderArray, nColCount);
-
- SetRedraw(FALSE);
-
- // All invisible columns must be place in the begining of the order-array
- int nColOrder = nColCount;
- for(int i = nVisibleCols - 1; i >= 0; --i)
- {
- CString colSetting;
- colSetting.Format(_T("ColumnData_%d"), i);
- int nColData = config.GetIntSetting(colSetting);
- for(int nCol = 0; nCol < nColCount; ++nCol)
- {
- // Check if already in array
- BOOL alreadyIncluded = false;
- for(int j = nColOrder; j < nColCount; ++j)
- if (pOrderArray[j] == nCol)
- {
- alreadyIncluded = true;
- break;
- }
- if (alreadyIncluded)
- continue;
-
- if (nColData == GetColumnData(nCol))
- {
- // Column still exists
- if (IsColumnAlwaysHidden(nCol))
- continue;
-
- CGridColumnTrait::ColumnState& columnState = GetColumnTrait(nCol)->GetColumnState();
- columnState.m_Visible = true;
- LoadColumnState(i, nCol, config);
- pOrderArray[--nColOrder] = nCol;
- break;
- }
- }
- }
-
- // Are there any always visible columns, that we must ensure are visible ?
- for(int nCol = nColCount - 1; nCol >= 0; --nCol)
- {
- if (!IsColumnAlwaysVisible(nCol))
- continue;
-
- BOOL visible = false;
- for(int i = nColOrder; i < nColCount; ++i)
- {
- if (pOrderArray[i] == nCol)
- {
- visible = true;
- break;
- }
- }
- if (!visible)
- {
- CGridColumnTrait::ColumnState& columnState = GetColumnTrait(nCol)->GetColumnState();
- columnState.m_Visible = true;
- pOrderArray[--nColOrder] = nCol;
- }
- }
-
- // Did we find any visible columns in the saved configuration ?
- if (nColOrder < nColCount)
- {
- // All remaining columns are marked as invisible
- while(nColOrder > 0)
- {
- // Find nCol som ikke er i array
- int nCol = -1;
- for(nCol = nColCount - 1; nCol >= 0; --nCol)
- {
- BOOL visible = false;
- for(int j = nColOrder; j < nColCount; ++j)
- {
- if (pOrderArray[j] == nCol)
- {
- visible = true;
- break;
- }
- }
- if (!visible)
- break;
- }
- ASSERT(nCol != -1);
- CGridColumnTrait::ColumnState& columnState = GetColumnTrait(nCol)->GetColumnState();
- columnState.m_OrgPosition = -1;
- columnState.m_OrgWidth = GetColumnWidth(nCol);
- SetColumnWidth(nCol, 0);
- columnState.m_Visible = false;
- ASSERT(nColOrder > 0);
- pOrderArray[--nColOrder] = nCol;
- }
-
- // Only update the column configuration if there are visible columns
- ASSERT(nColOrder == 0); // All entries in the order-array must be set
- SetColumnOrderArray(nColCount, pOrderArray);
- }
-
- delete [] pOrderArray;
-
- m_pColumnConfig = pColumnConfig;
-
- SetRedraw(TRUE);
- Invalidate(TRUE);
- UpdateWindow();
- }
-
- //------------------------------------------------------------------------
- //! Loads the column state of a single column
- //!
- //! @param nConfigCol The column index in the persisting interface
- //! @param nOwnerCol The column index in the owner list control
- //! @param config The interface for persisting the configuration
- //------------------------------------------------------------------------
- void CGridListCtrlEx::LoadColumnState(int nConfigCol, int nOwnerCol, CViewConfigSection& config)
- {
- CString colSetting;
- if (IsColumnResizable(nOwnerCol))
- {
- colSetting.Format(_T("ColumnWidth_%d"), nConfigCol);
- int width = config.GetIntSetting(colSetting);
- SetColumnWidth(nOwnerCol, width);
- }
- }
-
- //------------------------------------------------------------------------
- //! Saves the column configuration of the list control
- //!
- //! @param config The interface for persisting the configuration
- //------------------------------------------------------------------------
- void CGridListCtrlEx::SaveState(CViewConfigSection& config)
- {
- config.RemoveCurrentConfig(); // Reset the existing config
-
- int nColCount = GetColumnCount();
- int* pOrderArray = new int[nColCount];
- GetColumnOrderArray(pOrderArray, nColCount);
-
- int nVisibleCols = 0;
- for(int i = 0 ; i < nColCount; ++i)
- {
- int nCol = pOrderArray[i];
- int nColData = GetColumnData(nCol);
-
- if (IsColumnVisible(nCol))
- {
- CString colSetting;
- colSetting.Format(_T("ColumnData_%d"), nVisibleCols);
- config.SetIntSetting(colSetting, nColData);
-
- SaveColumnState(nVisibleCols, nCol, config);
-
- nVisibleCols++;
- }
- }
- config.SetIntSetting(_T("ColumnCount"), nVisibleCols);
-
- delete [] pOrderArray;
- }
-
-
- //------------------------------------------------------------------------
- //! Saves the column state of a single column
- //!
- //! @param nConfigCol The column index in the persisting interface
- //! @param nOwnerCol The column index in the owner list control
- //! @param config The interface for persisting the configuration
- //------------------------------------------------------------------------
- void CGridListCtrlEx::SaveColumnState(int nConfigCol, int nOwnerCol, CViewConfigSection& config)
- {
- CString colSetting;
- colSetting.Format(_T("ColumnWidth_%d"), nConfigCol);
- config.SetIntSetting(colSetting, GetColumnWidth(nOwnerCol));
- }
-
- //------------------------------------------------------------------------
- //! Is there a column configuration editor available for this column ?
- //!
- //! @param nCol The index of the column
- //! @param strTitle Title to show in the context menu when right-clicking the column
- //! @return Column editor available (true / false)
- //------------------------------------------------------------------------
- BOOL CGridListCtrlEx::HasColumnEditor(int nCol, CString& strTitle)
- {
- return false;
- }
-
- //------------------------------------------------------------------------
- //! Open the column configuration editor for the column (If one available)
- //!
- //! @param nCol The index of the column
- //------------------------------------------------------------------------
- void CGridListCtrlEx::OpenColumnEditor(int nCol)
- {
- }
-
- //------------------------------------------------------------------------
- //! Is there a column picker available that can add / remove columns
- //!
- //! @param strTitle Title to show in the context menu when right-clicking the column
- //! @return Column picker available (true / false)
- //------------------------------------------------------------------------
- BOOL CGridListCtrlEx::HasColumnPicker(CString& strTitle)
- {
- return false;
- }
-
- //------------------------------------------------------------------------
- //! Open the column picker for the list control
- //------------------------------------------------------------------------
- void CGridListCtrlEx::OpenColumnPicker()
- {
- }
-
- //------------------------------------------------------------------------
- //! Has the ability to reset the column configuration to its default configuration
- //!
- //! @param strTitle Title to show in the context menu when right-clicking the column
- //! @return Default column configuration is available (true / false)
- //------------------------------------------------------------------------
- BOOL CGridListCtrlEx::HasColumnDefaultState(CString& strTitle)
- {
- if (m_pColumnConfig == NULL)
- return false;
-
- strTitle = _T("Reset columns");
- return m_pColumnConfig->HasDefaultConfig();
- }
-
- //------------------------------------------------------------------------
- //! Reset the column configuration to its default configuration
- //------------------------------------------------------------------------
- void CGridListCtrlEx::ResetColumnDefaultState()
- {
- if (m_pColumnConfig == NULL)
- return;
-
- m_pColumnConfig->ResetConfigDefault();
- LoadState(*m_pColumnConfig);
- }
-
- //------------------------------------------------------------------------
- //! Can switch between multiple column configurations
- //!
- //! @param profiles List of available column profiles
- //! @param strTitle Title to show in the context menu when right-clicking the column
- //! @return Name of the current column profile
- //------------------------------------------------------------------------
- CString CGridListCtrlEx::HasColumnProfiles(CSimpleArray<CString>& profiles, CString& strTitle)
- {
- if (m_pColumnConfig == NULL)
- return _T("");
-
- strTitle = _T("Column Profiles");
- m_pColumnConfig->GetProfiles(profiles);
- return m_pColumnConfig->GetActiveProfile();
- }
-
- //------------------------------------------------------------------------
- //! Switch to different column configurations profile
- //!
- //! @param strProfile List of available column profiles
- //------------------------------------------------------------------------
- void CGridListCtrlEx::SwichColumnProfile(const CString& strProfile)
- {
- if (m_pColumnConfig == NULL)
- return;
-
- // Save the current configuration before switching to the new one
- SaveState(*m_pColumnConfig);
- m_pColumnConfig->SetActiveProfile(strProfile);
- LoadState(*m_pColumnConfig);
- }
-
- //------------------------------------------------------------------------
- //! Called after a column has been added / removed
- //------------------------------------------------------------------------
- void CGridListCtrlEx::OnSaveStateColumnPick()
- {
- if (m_pColumnConfig != NULL)
- SaveState(*m_pColumnConfig);
- }
-
- //------------------------------------------------------------------------
- //! Called after a column has been resized
- //------------------------------------------------------------------------
- void CGridListCtrlEx::OnSaveStateColumnResize()
- {
- if (m_pColumnConfig != NULL)
- SaveState(*m_pColumnConfig);
- }
-
- //------------------------------------------------------------------------
- //! Called when the list control looses focus to another control
- //------------------------------------------------------------------------
- void CGridListCtrlEx::OnSaveStateKillFocus()
- {
- if (m_pColumnConfig != NULL)
- SaveState(*m_pColumnConfig);
- }
-
- //------------------------------------------------------------------------
- //! Checks if the current OS version against the requested OS version
- //!
- //! @param requestOS The full version number of the OS required (Ex 0x0600)
- //------------------------------------------------------------------------
- BOOL CGridListCtrlEx::CheckOSVersion(WORD requestOS)
- {
- static WORD fullver = 0;
- if (fullver == 0)
- {
- OSVERSIONINFO osver = {0};
- osver.dwOSVersionInfoSize = sizeof(osver);
- VERIFY( GetVersionEx(&osver) );
- fullver = MAKEWORD(osver.dwMinorVersion, osver.dwMajorVersion);
- }
- return requestOS <= fullver;
- }
-
- namespace
- {
- BOOL IsCommonControlsEnabled()
- {
- BOOL commoncontrols = false;
-
- // Test if application has access to common controls
- HMODULE hinstDll = ::LoadLibrary(_T("comctl32.dll"));
- if (hinstDll)
- {
- DLLGETVERSIONPROC pDllGetVersion = (DLLGETVERSIONPROC)::GetProcAddress(hinstDll, "DllGetVersion");
- if (pDllGetVersion != NULL)
- {
- DLLVERSIONINFO dvi = {0};
- dvi.cbSize = sizeof(dvi);
- HRESULT hRes = pDllGetVersion ((DLLVERSIONINFO*) &dvi);
- if (SUCCEEDED(hRes))
- commoncontrols = dvi.dwMajorVersion >= 6;
- }
- ::FreeLibrary(hinstDll);
- }
- return commoncontrols;
- }
-
- BOOL IsThemeEnabled()
- {
- BOOL XPStyle = false;
- BOOL (__stdcall * pIsAppThemed)();
- BOOL (__stdcall * pIsThemeActive)();
-
- // Test if operating system has themes enabled
- HMODULE hinstDll = ::LoadLibrary(_T("UxTheme.dll"));
- if (hinstDll)
- {
- (FARPROC&)pIsAppThemed = ::GetProcAddress(hinstDll, "IsAppThemed");
- (FARPROC&)pIsThemeActive = ::GetProcAddress(hinstDll, "IsThemeActive");
- if (pIsAppThemed != NULL && pIsThemeActive != NULL)
- {
- if (pIsAppThemed() && pIsThemeActive())
- {
- // Test if application has themes enabled by loading the proper DLL
- XPStyle = IsCommonControlsEnabled();
- }
- }
- ::FreeLibrary(hinstDll);
- }
- return XPStyle;
- }
-
- LRESULT EnableWindowTheme(HWND hwnd, LPCWSTR classList, LPCWSTR subApp, LPCWSTR idlist)
- {
- LRESULT lResult = S_FALSE;
-
- HRESULT (__stdcall * pSetWindowTheme)(HWND hwnd, LPCWSTR pszSubAppName, LPCWSTR pszSubIdList);
- HANDLE (__stdcall * pOpenThemeData)(HWND hwnd, LPCWSTR pszClassList);
- HRESULT (__stdcall * pCloseThemeData)(HANDLE hTheme);
-
- HMODULE hinstDll = ::LoadLibrary(_T("UxTheme.dll"));
- if (hinstDll)
- {
- (FARPROC&)pOpenThemeData = ::GetProcAddress(hinstDll, "OpenThemeData");
- (FARPROC&)pCloseThemeData = ::GetProcAddress(hinstDll, "CloseThemeData");
- (FARPROC&)pSetWindowTheme = ::GetProcAddress(hinstDll, "SetWindowTheme");
- if (pSetWindowTheme && pOpenThemeData && pCloseThemeData)
- {
- HANDLE theme = pOpenThemeData(hwnd, classList);
- if (theme != NULL)
- {
- VERIFY(pCloseThemeData(theme) == S_OK);
- lResult = pSetWindowTheme(hwnd, subApp, idlist);
- }
- }
- ::FreeLibrary(hinstDll);
- }
- return lResult;
- }
- }
-
- //------------------------------------------------------------------------
- //! Activate visual style for the list control (Vista Theme)
- //!
- //! @param bValue Specifies whether the visual styles should be enabled or not
- //! @return S_FALSE if visual styles could not be enabled
- //------------------------------------------------------------------------
- LRESULT CGridListCtrlEx::EnableVisualStyles(BOOL bValue)
- {
- if (!IsThemeEnabled())
- {
- m_UsingVisualStyle = false;
- return S_FALSE;
- }
-
- if (!CheckOSVersion(0x0600))
- {
- m_UsingVisualStyle = false;
- return S_FALSE;
- }
-
- LRESULT rc = S_FALSE;
- if (bValue)
- rc = EnableWindowTheme(GetSafeHwnd(), L"ListView", L"Explorer", NULL);
- else
- rc = EnableWindowTheme(GetSafeHwnd(), L"", L"", NULL);
-
- if (bValue && rc == S_OK)
- {
- // OBS! Focus retangle is not painted properly without double-buffering
- m_UsingVisualStyle = true;
- #if (_WIN32_WINNT >= 0x501)
- if (CheckOSVersion(0x501))
- SetExtendedStyle(LVS_EX_DOUBLEBUFFER | GetExtendedStyle());
- #endif
- }
- else
- {
- m_UsingVisualStyle = false;
- }
-
- return rc;
- }
-
- //------------------------------------------------------------------------
- //! Configures the initial style of the list control when the it is created
- //------------------------------------------------------------------------
- void CGridListCtrlEx::OnCreateStyle()
- {
- // Will be called twice when placed inside a CView
-
- // Not using VERIFY / ASSERT as MessageBox cannot be opened during subclassing/creating
- if (!(GetStyle() & LVS_REPORT))
- DebugBreak(); // CListCtrl must be created with style LVS_REPORT
- if (GetStyle() & LVS_OWNERDRAWFIXED)
- DebugBreak(); // CListCtrl must be created without style LVS_OWNERDRAWFIXED
-
- ModifyStyle(0, LVS_SHOWSELALWAYS);
-
- SetExtendedStyle(GetExtendedStyle() | LVS_EX_FULLROWSELECT);
- SetExtendedStyle(GetExtendedStyle() | LVS_EX_HEADERDRAGDROP);
- SetExtendedStyle(GetExtendedStyle() | LVS_EX_GRIDLINES);
- SetExtendedStyle(GetExtendedStyle() | LVS_EX_SUBITEMIMAGES);
- #if (_WIN32_WINNT >= 0x501)
- if (CheckOSVersion(0x501))
- SetExtendedStyle(GetExtendedStyle() | LVS_EX_DOUBLEBUFFER);
- #endif
-
- // Enable Vista-look if possible
- EnableVisualStyles(m_bUseVisualStyles);
-
- // Enable the standard tooltip
- EnableToolTips(TRUE);
-
- // Disable the builtin tooltip (if available)
- CToolTipCtrl* pToolTipCtrl = (CToolTipCtrl*)CWnd::FromHandle((HWND)::SendMessage(m_hWnd, LVM_GETTOOLTIPS, 0, 0L));
- if (pToolTipCtrl != NULL && pToolTipCtrl->m_hWnd != NULL)
- pToolTipCtrl->Activate(FALSE);
-
- RegisterDropTarget();
- }
-
- //------------------------------------------------------------------------
- //! WM_CREATE message handler. Called when inside a CView.
- //!
- //! @param lpCreateStruct Pointer to a CREATESTRUCT structure that contains information about the list control object being created.
- //------------------------------------------------------------------------
- int CGridListCtrlEx::OnCreate(LPCREATESTRUCT lpCreateStruct)
- {
- // Will not be called when placed inside a CDialog
- int rc = CListCtrl::OnCreate(lpCreateStruct);
- if (rc == 0)
- OnCreateStyle();
-
- return rc;
- }
-
- //------------------------------------------------------------------------
- //! Normally used for subclassing controls, but here used to configure
- //! initial style when list control is created.
- //------------------------------------------------------------------------
- void CGridListCtrlEx::PreSubclassWindow()
- {
- // Changes made to style will not having any effect when placed in a CView
- CListCtrl::PreSubclassWindow();
- OnCreateStyle();
- }
-
-
- //------------------------------------------------------------------------
- //! Inserts a new column in the list control, and gives the option to customize the column using a trait
- //!
- //! @param nCol Index of the new column
- //! @param strColumnHeading Title of the new column
- //! @param nFormat Text alignment of the new column
- //! @param nWidth Width of the new column
- //! @param nSubItem Unique identifier used to recognize the column independent of index
- //! @param pTrait Column trait interface for the new column
- //! @return The index of the new column if successful or -1 otherwise.
- //------------------------------------------------------------------------
- int CGridListCtrlEx::InsertColumnTrait(int nCol, const CString& strColumnHeading, int nFormat, int nWidth, int nSubItem, CGridColumnTrait* pTrait)
- {
- VERIFY(m_ColumnTraits.GetSize() == GetColumnCount());
-
- if (pTrait != NULL)
- {
- if (pTrait->GetColumnState().m_AlwaysHidden)
- {
- nWidth = 0;
- pTrait->GetColumnState().m_Visible = false;
- }
-
- // nCol specifies the position, if nCol is greater than count,
- // then insert as last
- if (nCol >= GetHeaderCtrl()->GetItemCount())
- {
- nCol = GetHeaderCtrl()->GetItemCount();
- InsertColumnTrait(nCol, pTrait);
- }
- else
- {
- InsertColumnTrait(nCol, pTrait);
- }
- }
-
- int index = InsertColumn(nCol, static_cast<LPCTSTR>(strColumnHeading), nFormat, nWidth, nSubItem);
- if (index != -1)
- {
- VERIFY( index == nCol );
- GetColumnTrait(nCol)->OnInsertColumn(*this, nCol);
- }
- else
- DeleteColumnTrait(nCol);
- return index;
- }
-
- //------------------------------------------------------------------------
- //! Inserts the label column (first column) with invisible state
- //! The label column behaves differently from the rest of the columns,
- //! and to get the uniform look, then it should be hidden away.
- //! - It has a special margin, which no other column has
- //! - When dragged to another position than the first, then it looses it special margin
- //!
- //! @return The index of the new column if successful or -1 otherwise.
- //------------------------------------------------------------------------
- int CGridListCtrlEx::InsertHiddenLabelColumn()
- {
- // Must be the label column
- VERIFY(GetHeaderCtrl()->GetItemCount() == 0);
- VERIFY(m_ColumnTraits.GetSize() == 0);
-
- CGridColumnTrait* pColumTrait = new CGridColumnTrait;
- pColumTrait->GetColumnState().m_AlwaysHidden = true;
- return InsertColumnTrait(0, _T(""), LVCFMT_LEFT, -1, -1, pColumTrait);
- }
-
- //------------------------------------------------------------------------
- //! Retrieves the header control of a list control.
- //!
- //! @return A pointer to the header control, used by the list control.
- //------------------------------------------------------------------------
- const CHeaderCtrl* CGridListCtrlEx::GetHeaderCtrl() const
- {
- ASSERT(::IsWindow(m_hWnd));
-
- HWND hWnd = (HWND) ::SendMessage(m_hWnd, LVM_GETHEADER, 0, 0);
- if (hWnd == NULL)
- return NULL;
- else
- return (const CHeaderCtrl*) CHeaderCtrl::FromHandle(hWnd);
- }
-
- //------------------------------------------------------------------------
- //! Retrieves the number of columns from the header control.
- //!
- //! @return Number of header control items if successful; otherwise – 1.
- //------------------------------------------------------------------------
- int CGridListCtrlEx::GetColumnCount() const
- {
- return GetHeaderCtrl()->GetItemCount();
- }
-
- //------------------------------------------------------------------------
- //! Retrieves the font used to draw cells in the list control
- //!
- //! @return A pointer to the current font used by the list control.
- //------------------------------------------------------------------------
- CFont* CGridListCtrlEx::GetCellFont()
- {
- if (m_CellFont.GetSafeHandle() == NULL)
- return GetFont();
- return &m_CellFont;
- }
-
- //------------------------------------------------------------------------
- //! Takes the current font and increases the font with the given margin
- //! multiplier. Increases the row-height but keeps the cell font intact.
- //! Gives more room for the grid-cell editors and their border.
- //!
- //! @param margin Multiplier for how much to increase the font size
- //------------------------------------------------------------------------
- void CGridListCtrlEx::SetCellMargin(double margin)
- {
- LOGFONT lf = {0};
- VERIFY(GetFont()->GetLogFont(&lf) != 0);
- if (static_cast<HFONT>(m_CellFont))
- VERIFY( m_CellFont.DeleteObject() );
- VERIFY( m_CellFont.CreateFontIndirect(&lf) );
-
- lf.lfHeight = (int)( lf.lfHeight * margin );
- lf.lfWidth = (int)( lf.lfWidth * margin );
- if (static_cast<HFONT>(m_GridFont))
- VERIFY( m_GridFont.DeleteObject() );
- VERIFY( m_GridFont.CreateFontIndirect(&lf) );
-
- m_Margin = -1; // Avoid loop in WM_SETFONT message handler
- CListCtrl::SetFont(&m_GridFont);
- m_Margin = margin;
-
- GetHeaderCtrl()->SetFont(&m_CellFont);
- CToolTipCtrl* pToolTipCtrl = (CToolTipCtrl*)CWnd::FromHandle((HWND)::SendMessage(m_hWnd, LVM_GETTOOLTIPS, 0, 0L));
- if (pToolTipCtrl != NULL && pToolTipCtrl->m_hWnd != NULL)
- pToolTipCtrl->SetFont(&m_CellFont);
- }
-
- //------------------------------------------------------------------------
- //! WM_SETFONT message handler. For re-applying margin if font changes
- //!
- //! @param wParam Handle to the font (HFONT), where NULL means default font
- //! @param lParam The low-order word of lParam specifies whether to redraw
- //! @return Not used
- //------------------------------------------------------------------------
- LRESULT CGridListCtrlEx::OnSetFont(WPARAM wParam, LPARAM lParam)
- {
- LRESULT result = DefWindowProc(WM_SETFONT, wParam, lParam);
- if (m_Margin >= 0)
- SetCellMargin(m_Margin);
- return result;
- }
-
- //------------------------------------------------------------------------
- //! The column version of GetItemData(), one can specify an unique
- //! identifier when using InsertColumn()
- //!
- //! @param nCol Index of the column
- //! @return Unique identifier of the column specified
- //------------------------------------------------------------------------
- int CGridListCtrlEx::GetColumnData(int nCol) const
- {
- LVCOLUMN lvc = {0};
- lvc.mask = LVCF_SUBITEM;
- VERIFY( GetColumn(nCol, &lvc) );
- return lvc.iSubItem;
- }
-
- //------------------------------------------------------------------------
- //! Get column position in the CHeaderCtrl's display order array
- //!
- //! @param nCol Index of the column
- //! @return Column offset is in left-to-right order. For example, zero indicates the leftmost column.
- //------------------------------------------------------------------------
- int CGridListCtrlEx::GetColumnOrder(int nCol) const
- {
- LVCOLUMN lvc = {0};
- lvc.mask = LVCF_ORDER;
- VERIFY( GetColumn(nCol, &lvc) );
- return lvc.iOrder;
- }
-
- //------------------------------------------------------------------------
- //! Retrieve column title of a column in the list control
- //!
- //! @param nCol Index of the column
- //! @return Column header text of the specified column
- //------------------------------------------------------------------------
- CString CGridListCtrlEx::GetColumnHeading(int nCol) const
- {
- // Retrieve column-title
- LVCOLUMN lvc = {0};
- lvc.mask = LVCF_TEXT;
- TCHAR sColText[256];
- lvc.pszText = sColText;
- lvc.cchTextMax = sizeof(sColText) - 1;
- VERIFY( GetColumn(nCol, &lvc) );
- return lvc.pszText;
- }
-
- //------------------------------------------------------------------------
- //! Retrieve row with the LVIS_FOCUSED state flag set
- //!
- //! @return The index of the row if successful, or -1 otherwise.
- //------------------------------------------------------------------------
- int CGridListCtrlEx::GetFocusRow() const
- {
- return GetNextItem(-1, LVNI_FOCUSED);
- }
-
- //------------------------------------------------------------------------
- //! Sets LVIS_FOCUSED state flag for the specified row
- //!
- //! @param nRow The index of the row
- //------------------------------------------------------------------------
- void CGridListCtrlEx::SetFocusRow(int nRow)
- {
- SetItemState(nRow, LVIS_FOCUSED, LVIS_FOCUSED);
- }
-
- //------------------------------------------------------------------------
- //! Checks if the LVIS_SELECTED state flag set for the specified row
- //!
- //! @param nRow The index of the row
- //! @return True if the row is selected
- //------------------------------------------------------------------------
- BOOL CGridListCtrlEx::IsRowSelected(int nRow) const
- {
- return (GetItemState(nRow, LVIS_SELECTED) & LVIS_SELECTED) == LVIS_SELECTED;
- }
-
- //------------------------------------------------------------------------
- //! Sets the LVIS_SELECTED state flag for the specified row
- //!
- //! @param nRow The index of the row. -1 means all rows
- //! @param bSelect Whether row should be selected or not
- //! @return Nonzero if successful; otherwise zero.
- //------------------------------------------------------------------------
- BOOL CGridListCtrlEx::SelectRow(int nRow, BOOL bSelect)
- {
- return SetItemState(nRow, bSelect ? LVIS_SELECTED : 0, LVIS_SELECTED);
- }
-
- //------------------------------------------------------------------------
- //! Improved version of GetSubItemRect().
- //! - It doesn't return entire row-rect when using LVIR_BOUNDS for label-column (nCol==0)
- //! - It supports LVIR_LABEL for sub-items (nCol>0)
- //! - It supports LVIR_BOUNDS when column width is less than subitem image width
- //!
- //! @param nRow The index of the row
- //! @param nCol The index of the column
- //! @param nCode Determines the portion of the bounding rectangle (of the list view subitem) to be retrieved.
- //! @param rect Reference to a CRect object that contains the coordinates of the cell's bounding rectangle.
- //! @return Nonzero if successful; otherwise zero.
- //------------------------------------------------------------------------
- BOOL CGridListCtrlEx::GetCellRect(int nRow, int nCol, UINT nCode, CRect& rect)
- {
- if (GetSubItemRect(nRow, nCol, nCode, rect) == FALSE)
- return FALSE;
-
- if (nCode == LVIR_BOUNDS)
- {
- // Find the left and right of the cell-rectangle using the CHeaderCtrl
- CRect colRect;
- if (GetHeaderCtrl()->GetItemRect(nCol, colRect) == FALSE)
- return FALSE;
-
- if (nCol == 0)
- {
- // Fix bug where LVIR_BOUNDS gives the entire row for nCol==0
- CRect labelRect;
- if (GetSubItemRect(nRow, nCol, LVIR_LABEL, labelRect) == FALSE)
- return FALSE;
-
- rect.right = labelRect.right;
- rect.left = labelRect.right - colRect.Width();
- }
- else
- {
- // Fix bug when width is smaller than subitem image width
- rect.right = rect.left + colRect.Width();
- }
- }
-
- if (nCode == LVIR_ICON)
- {
- if (nCol > 0 && !(GetExtendedStyle() & LVS_EX_SUBITEMIMAGES))
- return FALSE; // no image in subitem
-
- int nImage = GetCellImage(nRow, nCol);
- if (nImage == I_IMAGECALLBACK)
- return FALSE; // no image
-
- return TRUE;
- }
-
- if (nCode == LVIR_LABEL && nCol > 0)
- {
- if (!(GetExtendedStyle() & LVS_EX_SUBITEMIMAGES))
- return TRUE; // no image in subitem
-
- int nImage = GetCellImage(nRow, nCol);
- if (nImage == I_IMAGECALLBACK)
- return TRUE; // No image in subitem
-
- CRect iconRect;
- if (GetSubItemRect(nRow, nCol, LVIR_ICON, iconRect) == FALSE)
- return FALSE;
-
- rect.left += iconRect.Width();
- }
-
- return TRUE;
- }
-
- //------------------------------------------------------------------------
- //! Replicates the SubItemHitTest() but in a const version. Finds the cell
- //! below the given mouse cursor position.
- //!
- //! @param pt The position to hit test, in client coordinates.
- //! @param nRow The index of the row (Returns -1 if no row)
- //! @param nCol The index of the column (Returns -1 if no column)
- //------------------------------------------------------------------------
- void CGridListCtrlEx::CellHitTest(const CPoint& pt, int& nRow, int& nCol) const
- {
- nRow = -1;
- nCol = -1;
-
- LVHITTESTINFO lvhti = {0};
- lvhti.pt = pt;
- nRow = ListView_SubItemHitTest(m_hWnd, &lvhti); // SubItemHitTest is non-const
- nCol = lvhti.iSubItem;
- if (!(lvhti.flags & LVHT_ONITEM))
- nRow = -1;
- }
-
- //------------------------------------------------------------------------
- //! Checks if the current cell is using callback to retrieve its text value
- //!
- //! @param nRow The index of the row
- //! @param nCol The index of the column
- //! @return Returns true if the cell is using call back to retrieve its text value
- //------------------------------------------------------------------------
- BOOL CGridListCtrlEx::IsCellCallback(int nRow, int nCol) const
- {
- if (GetStyle() & LVS_OWNERDATA)
- return true;
-
- LVITEM lvi = {0};
- lvi.iItem = nRow;
- lvi.iSubItem = nCol;
- lvi.mask = LVIF_TEXT | LVIF_NORECOMPUTE;
- VERIFY( GetItem( &lvi ) );
- return lvi.pszText == LPSTR_TEXTCALLBACK;
- }
-
- //------------------------------------------------------------------------
- //! Retrieves the icon index of the specified cell
- //!
- //! @param nRow The index of the row
- //! @param nCol The index of the column
- //! @return Index of the cell's icon in the control's image list (I_IMAGECALLBACK means no image)
- //------------------------------------------------------------------------
- int CGridListCtrlEx::GetCellImage(int nRow, int nCol) const
- {
- LVITEM lvi = {0};
- lvi.iItem = nRow;
- lvi.iSubItem = nCol;
- lvi.mask = LVIF_IMAGE;
- VERIFY( GetItem( &lvi ) );
- return lvi.iImage;
- }
-
- //------------------------------------------------------------------------
- //! Sets the icon of the specified cell
- //!
- //! @param nRow The index of the row
- //! @param nCol The index of the column
- //! @param nImageId The icon index in the list control image list
- //! @return Nonzero if successful; otherwise zero.
- //------------------------------------------------------------------------
- BOOL CGridListCtrlEx::SetCellImage(int nRow, int nCol, int nImageId)
- {
- LVITEM lvitem = {0};
- lvitem.mask = LVIF_IMAGE;
- lvitem.iItem = nRow;
- lvitem.iSubItem = nCol;
- lvitem.iImage = nImageId; // I_IMAGENONE (Indent but no image), I_IMAGECALLBACK
- return SetItem(&lvitem);
- }
-
- //------------------------------------------------------------------------
- //! Changes the focus cell.
- //! Override this method and set m_FocusCell = -1 if wanting to disable subitem focus
- //!
- //! @param nCol The index of the column
- //! @param bRedraw Should the focus row be redrawn ? (true / false)
- //------------------------------------------------------------------------
- void CGridListCtrlEx::SetFocusCell(int nCol, BOOL bRedraw)
- {
- m_FocusCell = nCol;
- if (bRedraw)
- {
- int nFocusRow = GetFocusRow();
- if (nFocusRow >= 0)
- {
- CRect itemRect;
- VERIFY( GetItemRect(nFocusRow, itemRect, LVIR_BOUNDS) );
- InvalidateRect(itemRect);
- UpdateWindow();
- }
- }
- }
-
- //------------------------------------------------------------------------
- //! Shifts the cell focus left or right in the same row
- //!
- //! @param bMoveRight Specifies whether the cell focus should be left or right
- //------------------------------------------------------------------------
- void CGridListCtrlEx::MoveFocusCell(BOOL bMoveRight)
- {
- if (GetItemCount() <= 0)
- {
- SetFocusCell(-1); // Entire row selected
- return;
- }
-
- if (GetFocusCell() == -1)
- {
- // Entire row already selected
- if (bMoveRight)
- {
- // Change to the first column in the current order
- SetFocusCell( GetFirstVisibleColumn() );
- }
- }
- else
- {
- // Convert focus-cell to order index
- int nOrderIndex = -1;
- for(int i = 0; i < GetHeaderCtrl()->GetItemCount(); ++i)
- {
- int nCol = GetHeaderCtrl()->OrderToIndex(i);
- if (nCol == GetFocusCell())
- {
- nOrderIndex = i;
- break;
- }
- }
-
- // Move to the following column
- if (bMoveRight)
- nOrderIndex++;
- else
- nOrderIndex--;
-
- // Convert order-index to focus cell
- if (nOrderIndex >= 0 && nOrderIndex < GetHeaderCtrl()->GetItemCount())
- {
- int nCol = GetHeaderCtrl()->OrderToIndex(nOrderIndex);
- if (IsColumnVisible(nCol))
- SetFocusCell(nCol);
- else if (!bMoveRight)
- SetFocusCell(-1); // Entire row selection
- }
- else if (!bMoveRight)
- SetFocusCell(-1); // Entire row selection
- }
-
- // Ensure the column is visible
- if (GetFocusCell() >= 0)
- {
- VERIFY( EnsureColumnVisible(GetFocusCell(), false) );
- }
-
- SetFocusCell(GetFocusCell(), true);
- }
-
-
- //------------------------------------------------------------------------
- //! Scrolls the view, so the column becomes visible
- //!
- //! http://www.codeguru.com/cpp/controls/listview/columns/article.php/c931/
- //!
- //! @param nCol The index of the column
- //! @param bPartialOK Is partially visible good enough ?
- //! @return Nonzero if successful; otherwise zero.
- //------------------------------------------------------------------------
- BOOL CGridListCtrlEx::EnsureColumnVisible(int nCol, BOOL bPartialOK)
- {
- if (nCol < 0 || nCol >= GetHeaderCtrl()->GetItemCount())
- return FALSE;
-
- CRect rcHeader;
- if (GetHeaderCtrl()->GetItemRect(nCol, rcHeader) == FALSE)
- return FALSE;
-
- CRect rcClient;
- GetClientRect(&rcClient);
-
- int nOffset = GetScrollPos(SB_HORZ);
-
- if(bPartialOK)
- {
- if((rcHeader.left - nOffset < rcClient.right) && (rcHeader.right - nOffset > 0))
- {
- return TRUE;
- }
- }
-
- int nScrollX = 0;
-
- if((rcHeader.Width() > rcClient.Width()) || (rcHeader.left - nOffset < 0))
- {
- nScrollX = rcHeader.left - nOffset;
- }
- else if(rcHeader.right - nOffset > rcClient.right)
- {
- nScrollX = rcHeader.right - nOffset - rcClient.right;
- }
-
- if(nScrollX != 0)
- {
- CSize size(nScrollX, 0);
- if (Scroll(size) == FALSE)
- return FALSE;
- }
-
- return TRUE;
- }
-
- //------------------------------------------------------------------------
- //! Retrieves the column index of the first visible column
- //!
- //! @return Column index of the first visible column (-1 if no visible columns)
- //------------------------------------------------------------------------
- int CGridListCtrlEx::GetFirstVisibleColumn()
- {
- int nColCount = GetHeaderCtrl()->GetItemCount();
- for(int i = 0; i < nColCount; ++i)
- {
- int nCol = GetHeaderCtrl()->OrderToIndex(i);
- if (IsColumnVisible(nCol))
- {
- return nCol;
- }
- }
- return -1;
- }
-
- //------------------------------------------------------------------------
- //! Changes the visible state of column.
- //! Hides a column by resizing the column width to zero and moving it to
- //! the outer left in the column order. Shows a column by returning it to
- //! its original position.
- //!
- //! @param nCol The index of the column
- //! @param bShow Specifies whether the column should be shown or hidden
- //! @return Nonzero if successful; otherwise zero.
- //------------------------------------------------------------------------
- BOOL CGridListCtrlEx::ShowColumn(int nCol, BOOL bShow)
- {
- if (!bShow && IsColumnAlwaysVisible(nCol))
- return FALSE;
-
- if (bShow && IsColumnAlwaysHidden(nCol))
- return FALSE;
-
- CGridColumnTrait* pTrait = GetColumnTrait(nCol);
- CGridColumnTrait::ColumnState& columnState = pTrait->GetColumnState();
-
- SetRedraw(FALSE);
-
- int nColCount = GetColumnCount();
- int* pOrderArray = new int[nColCount];
- VERIFY( GetColumnOrderArray(pOrderArray, nColCount) );
- if (bShow)
- {
- if (columnState.m_OrgPosition == -1)
- {
- // Restore the default position of the column (No column drag drop)
- columnState.m_OrgPosition = nCol;
-
- int nCurIndex = -1;
- for(int i = 0; i < nColCount ; ++i)
- {
- if (pOrderArray[i] == nCol)
- {
- nCurIndex = i;
- }
- else if (nCurIndex != -1)
- {
- if (!IsColumnVisible(pOrderArray[i]) && pOrderArray[i] > nCol)
- columnState.m_OrgPosition++;
-
- pOrderArray[nCurIndex] = pOrderArray[i];
- pOrderArray[i] = nCol;
- nCurIndex = i;
-
- // We want to move it to the original visible position
- if (i >= columnState.m_OrgPosition)
- {
- if ( (i + 1 == nColCount) || IsColumnVisible(pOrderArray[i + 1]) )
- break;
- }
- }
- else
- {
- if (pOrderArray[i] > nCol)
- columnState.m_OrgPosition++;
- }
- }
- }
- else
- {
- // Restore the last position of the column (Support column drag-drop)
- int nColOffSet = 0;
- int nCurIndex = -1;
- for(int i = 0; i < nColCount ; ++i)
- {
- if (pOrderArray[i] == nCol)
- {
- nCurIndex = i;
- columnState.m_OrgPosition += nColOffSet;
- }
- else if (nCurIndex != -1)
- {
- pOrderArray[nCurIndex] = pOrderArray[i];
- pOrderArray[i] = nCol;
- nCurIndex = i;
-
- // We want to move it to the original visible position
- if (i >= columnState.m_OrgPosition)
- {
- if ( (i + 1 == nColCount) || IsColumnVisible(pOrderArray[i + 1]) )
- break;
- }
- }
- else
- {
- if (GetColumnTrait(pOrderArray[i])->GetColumnState().m_OrgPosition != -1)
- {
- // Other columns have been hidden after, this column was hidden
- // - The other column was originally placed before this column (Showing this column changes the original position of the other column)
- if (GetColumnTrait(pOrderArray[i])->GetColumnState().m_OrgPosition <= columnState.m_OrgPosition)
- GetColumnTrait(pOrderArray[i])->GetColumnState().m_OrgPosition--;
- // - The other column was originally placed after this column (This column needs to adjust original position)
- if (GetColumnTrait(pOrderArray[i])->GetColumnState().m_OrgPosition >= columnState.m_OrgPosition)
- nColOffSet++;
- }
- }
- }
- }
- }
- else
- {
- // Move the column to the front of the display order list
- int nCurIndex(-1);
- for(int i = nColCount - 1; i >= 0 ; --i)
- {
- if (pOrderArray[i] == nCol)
- {
- // Backup the current position of the column
- columnState.m_OrgPosition = i;
- nCurIndex = i;
- }
- else if (nCurIndex != -1)
- {
- pOrderArray[nCurIndex] = pOrderArray[i];
- pOrderArray[i] = nCol;
- nCurIndex = i;
- }
- }
- }
-
- // Validate that all column-ids are unique and are between 0 og nCount
- for(int i = 0; i < nColCount ; ++i)
- {
- ASSERT(pOrderArray[i] >= 0);
- ASSERT(pOrderArray[i] < nColCount);
- for(int j = 0; j < nColCount ; ++j)
- {
- if (j == i)
- continue;
-
- ASSERT(pOrderArray[i] != pOrderArray[j]);
- }
- }
-
- VERIFY( SetColumnOrderArray(nColCount, pOrderArray) );
- delete [] pOrderArray;
-
- if (bShow)
- {
- // Restore the column width
- columnState.m_Visible = true;
- VERIFY( SetColumnWidth(nCol, columnState.m_OrgWidth) );
- }
- else
- {
- // Backup the column width
- int orgWidth = GetColumnWidth(nCol);
- VERIFY( SetColumnWidth(nCol, 0) );
- columnState.m_Visible = false;
- columnState.m_OrgWidth = orgWidth;
- }
-
- OnSaveStateColumnPick();
-
- SetRedraw(TRUE);
- Invalidate(FALSE);
- return TRUE;
- }
-
- //------------------------------------------------------------------------
- //! Resizes the width of a column according the contents of the cells below
- //!
- //! @param nCol The index of the column
- //! @param bIncludeHeader Include the column header text the column width calculation
- //! @return Nonzero if successful; otherwise zero.
- //------------------------------------------------------------------------
- BOOL CGridListCtrlEx::SetColumnWidthAuto(int nCol, BOOL bIncludeHeader)
- {
- if (nCol == -1)
- {
- for(int i = 0; i < GetHeaderCtrl()->GetItemCount() ; ++i)
- {
- SetColumnWidthAuto(i, bIncludeHeader);
- }
- return TRUE;
- }
- else
- {
- if (bIncludeHeader)
- return SetColumnWidth(nCol, LVSCW_AUTOSIZE_USEHEADER);
- else
- return SetColumnWidth(nCol, LVSCW_AUTOSIZE);
- }
- }
-
- namespace
- {
- HBITMAP CreateSortBitmap(BOOL bAscending)
- {
- // Aquire the Display DC
- CDC* pDC = CDC::FromHandle(::GetDC(::GetDesktopWindow()));
- //create a memory dc
- CDC memDC;
- memDC.CreateCompatibleDC(pDC);
-
- //Create a memory bitmap
- CBitmap newbmp;
- CRect rcIcon(0, 0, 16, 16);
- newbmp.CreateCompatibleBitmap(pDC, rcIcon.Height(), rcIcon.Width());
-
- //select the bitmap in the memory dc
- CBitmap* pOldBitmap = memDC.SelectObject(&newbmp);
-
- //make the bitmap white to begin with
- memDC.FillSolidRect(rcIcon.top, rcIcon.left, rcIcon.bottom, rcIcon.right, ::GetSysColor(COLOR_3DFACE));
-
- // Set up pens to use for drawing the triangle
- CPen penLight(PS_SOLID, 1, GetSysColor(COLOR_3DHILIGHT));
- CPen penShadow(PS_SOLID, 1, GetSysColor(COLOR_3DSHADOW));
- CPen* pOldPen = memDC.SelectObject( &penLight );
-
- int iOffset = (rcIcon.bottom - rcIcon.top) / 4;
-
- if( bAscending )
- {
- // draw the arrow pointing upwards.
- memDC.MoveTo( rcIcon.right - 2 * iOffset, iOffset);
- memDC.LineTo( rcIcon.right - iOffset, rcIcon.bottom - iOffset - 1 );
- memDC.LineTo( rcIcon.right - 3 * iOffset - 2, rcIcon.bottom - iOffset - 1 );
- (void)memDC.SelectObject( &penShadow );
- memDC.MoveTo( rcIcon.right - 3 * iOffset - 1, rcIcon.bottom - iOffset - 1 );
- memDC.LineTo( rcIcon.right - 2 * iOffset, iOffset - 1);
- }
- else
- {
- // draw the arrow pointing downwards.
- memDC.MoveTo( rcIcon.right - iOffset - 1, iOffset );
- memDC.LineTo( rcIcon.right - 2 * iOffset - 1, rcIcon.bottom - iOffset );
- (void)memDC.SelectObject( &penShadow );
- memDC.MoveTo( rcIcon.right - 2 * iOffset - 2, rcIcon.bottom - iOffset );
- memDC.LineTo( rcIcon.right - 3 * iOffset - 1, iOffset );
- memDC.LineTo( rcIcon.right - iOffset - 1, iOffset );
- }
-
- // Restore the pen
- memDC.SelectObject(pOldPen);
-
- //select old bitmap back into the memory dc
- memDC.SelectObject(pOldBitmap);
-
- return (HBITMAP)newbmp.Detach();
- }
- }
-
- //------------------------------------------------------------------------
- //! Puts a sort-icon in the column header of the specified column
- //!
- //! @param nCol The index of the column
- //! @param bAscending Should the arrow be up or down…
Large files files are truncated, but you can click here to view the full file