//-------------------------------------------------------------------
//
// $Id: CGridCtrl.h,v 1.10 2004/06/16 23:49:26 miezoo Exp $
// Author: Marius Negrutiu (18.05.2004 21:13:10)
// mailto://negrutiu@as.ro
//
//-------------------------------------------------------------------
#pragma once
#ifndef CGRIDCTRL_H
#define CGRIDCTRL_H
#define GRID_VERSION 0x0105 // version 1.5
#define DEFAULT_EDIT_LIMIT 100
#define DEFAULT_BUFFER_LENGTH 255
#define DEFAULT_TIMER_INCSEARCH 2500 // incremental search reset period (default 2.5 sec)
#define This const_cast<CGridCtrl*>(this)
#define ROW (int)mDraw.cd->nmcd.dwItemSpec
#define COL mDraw.cd->iSubItem
//
// enum CellType
//
enum CellType
{
CELL_REGULAR = 0, // regular cell (text (and image) only)
CELL_CUSTOMEDITOR, // editable cell (the OnCustomCellClick callback is called)
CELL_EDITBOX, // editable cell (edit box)
CELL_COMBOBOX, // editable cell (drop-down-list combo box)
CELL_EDITCOMBOBOX, // editable cell (drop-down combo box)
CELL_CHECKBOXON, // editable cell (check box ON)
CELL_CHECKBOXOFF, // editable cell (check box OFF)
CELL_SEPARATOR // not editable cell
};
//
// enum FontStyle
//
enum FontStyle
{
FONT_BOLD = 1,
FONT_ITALIC = 1 << 1,
FONT_UNDERLINE = 1 << 2,
FONT_STRIKEOUT = 1 << 3
};
//
// class CGridCtrl
//
class CGridCtrl: public CListCtrl
{
DECLARE_DYNAMIC(CGridCtrl)
public:
CGridCtrl();
virtual ~CGridCtrl();
/*
PURPOSE:
Scrolls the grid control so that the specified column gets visible
ARGUMENTS:
Col Column index
RETURN:
The amount of pixels necessary to scroll the
grid in order to make this column visible. If the
return value is 0, the column was already visible.
*/
int EnsureColVisible(IN int Col);
/*
PURPOSE:
Determines the cell that contains the supplied point
ARGUMENTS:
Pt The point in client coordinates
Row The hit cell row
Col The hit cell column
Rect The cell rectangle
RETURN:
TRUE if a cell is hit. FALSE == whitespace.
*/
BOOL CellHitTest(IN const CPoint& Pt,
OUT int &Row,
OUT int &Col,
OUT RECT *Rect = NULL OPTIONAL);
/*
PURPOSE:
Retrieve a cell bounding rectangle.
ARGUMENTS:
Self explanatory
RETURN:
TRUE for success
*/
bool GetCellRect( IN int Row,
IN int Col,
OUT RECT& Rect);
/*
PURPOSE:
Ensure the supplied rectangle does not exceed the
grid control's client area. (The rectangle is intersected
with the grid client rect)
ARGUMENTS:
Self explanatory
*/
void ValidateCellRect(IN OUT RECT* rect);
/*
PURPOSE:
Get the index of the focused item (this information is read
from the parent list control)
RETURN:
The index or -1 if no item has the focus
*/
int GetFocused() const;
/*
PURPOSE:
Get the focused cell (this information is read from the cached
coordinates)
*/
inline void GetFocusedCell(OUT int& Row, OUT int& Col) { Row = mRow, Col = mCol; };
/*
PURPOSE:
Select the specified cell and ensure it is visible.
ARGUMENTS:
Row ...
Col ...
DoRedraw If true, the cell that was previously selected
is redrawn for clearing the focus rectangle. Also,
the new selected cell is redrawn for painting
the focus rectangle.
RETURN:
TRUE if success
*/
bool SelectCell(IN int Row, IN int Col, IN bool DoRedraw = false);
/*
PURPOSE:
Deselect all (selected) items, select and focus the current cell
*/
void DeselectAll();
/*
PURPOSE:
Enter edit mode
ARGUMENTS:
Row
Col
CellRect If NULL, GetCellRect(...) is called automatically
RETURN:
TRUE if success and the inplace editor was created
*/
bool EditCell( IN int Row,
IN int Col,
IN const RECT* CellRect = NULL OPTIONAL);
/*
PURPOSE:
GetColumnCount
*/
inline int GetColumnCount() const { return This->GetHeaderCtrl()->GetItemCount(); };
/*
PURPOSE:
HasGridLines
*/
inline bool HasGridLines() const { return ((This->GetExtendedStyle() & LVS_EX_GRIDLINES) != 0); };
/*
PURPOSE:
Redraws the specified row. If CheckVisibility == true,
the row is redrawn only if its visible in the current view.
*/
void RedrawItem(IN int Row, IN bool CheckVisibility = true);
/*
PURPOSE:
Get/set the in-place editors text limit. This limit prevents
large string typing. The editors that uses this information
are EDITBOX-es and EDITCOMBOBOX-es.
*/
inline UINT16 GetInplaceEditLimit() const { return mEditLen; };
void SetInplaceEditLimit(UINT16 Limit) { mEditLen = Limit; };
/*
PURPOSE:
CGridCtrl has an internal buffer used for any string operation.
This buffer MUST be large enough to carry any string displayed by
the grid control.
The following routines handle its size.
*/
inline UINT16 GetStringBufferLen() const { return mBufferLen; };
void SetStringBufferLen(UINT16 Len);
/*
PURPOSE:
Enable/disable grid's incremental search support.
*/
inline bool GetIncrementalSearch() const { return mIncSearch; };
inline void SetInctementalSearch(bool Enable = true) { mIncSearch = Enable; };
/*
PURPOSE:
Controls the time after an incremental search is reset.
*/
inline UINT16 GetIncrementalSearchTimer() const { return mIncSearchTimer; };
inline void SetIncrementalSearchTimer(IN UINT16 msecs) { mIncSearchTimer = msecs; };
/*
PURPOSE:
Set/reset drawing colors
*/
inline void SetColors( COLORREF ColorFrame,
COLORREF ColorNormalFill,
COLORREF ColorSelFill,
COLORREF ColorBtnFill,
COLORREF ColorNormalText,
COLORREF ColorSelText) { mDraw.SetColors(ColorFrame, ColorNormalFill, ColorSelFill, ColorBtnFill, ColorNormalText, ColorSelText); CacheVisuals(); };
inline void SetColorsToDefault() { mDraw.ResetColors(); CacheVisuals(); };
protected:
DECLARE_MESSAGE_MAP()
/*
PURPOSE:
Cache colors and generate bitmaps.
*/
virtual void CacheVisuals();
/*
PURPOSE:
Window message handlers
*/
afx_msg virtual void OnLButtonDown(UINT nFlags, CPoint point);
afx_msg virtual BOOL OnLClick(NMHDR* hdr, LRESULT* res);
afx_msg virtual void OnLButtonDblClk(UINT nFlags, CPoint point);
afx_msg virtual void OnRButtonDown(UINT nFlags, CPoint point);
afx_msg virtual BOOL OnRClick(NMHDR* hdr, LRESULT* res);
afx_msg virtual void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags);
afx_msg virtual void OnChar(UINT nChar, UINT nRepCnt, UINT nFlags);
afx_msg virtual void OnSetFocus(CWnd* pOldWnd);
afx_msg virtual void OnKillFocus(CWnd* pNewWnd);
afx_msg virtual BOOL OnEraseBkgnd(CDC *dc);
afx_msg virtual void OnSysColorChange();
afx_msg virtual LRESULT OnSetImageList(WPARAM wp, LPARAM lp);
afx_msg virtual void OnDestroy();
afx_msg virtual void OnTimer(UINT_PTR nIDEvent);
virtual void PreSubclassWindow(void);
virtual BOOL OnCommand(IN WPARAM wp, IN LPARAM lp);
/*
PURPOSE:
Callbacks for mouse events
NOTE:
Make sure you supercall the default implementation!
RETURN:
"OnCellClick" must return TRUE if any inplace editor was created.
*/
virtual bool OnCellLBtnDown( IN int Row,
IN int Col,
IN const RECT *CellRect,
IN const CPoint& Point);
virtual void OnCellLBtnUp( IN int Row,
IN int Col,
IN const RECT *CellRect,
IN const CPoint& Point);
virtual void OnCellRBtnDown( IN int Row,
IN int Col,
IN const RECT *CellRect,
IN const CPoint& Point);
virtual void OnCellRBtnUp( IN int Row,
IN int Col,
IN const RECT *CellRect,
IN const CPoint& Point);
virtual void OnCellDblClick( IN int Row,
IN int Col,
IN const RECT* CellRect);
/*
PURPOSE:
Called when a check-box cell was clicked
NOTE:
Make sure you supercall the default implementation!
*/
virtual void OnCheckBoxClick(int Row, int Col);
/*
PURPOSE:
Called when a custom-edit cell was clicked
*/
virtual void OnCustomCellClick(int Row, int Col);
/*
PURPOSE:
Called when an inplace combo box is about to be displayed. The routine should
provide the items for the combo box to be populated. It also may specify an icon
for each item. In this case it must set 'HasImages' to TRUE, and fill 'Images'
*/
virtual void OnGetComboBoxItems( IN int Row,
IN int Col,
OUT bool& HasImages,
OUT CStringList& Items,
OUT CArray<int, int>& Images);
/*
PURPOSE:
Called when an inplace editor is about to be destroyed. If the return value
is FALSE, the editor will not be destroyed and the edit operation will continue.
This is the right place to perform input validation.
*/
virtual bool OnEndInPlaceEdit( IN int Row,
IN int Col,
IN bool Canceled,
IN const TCHAR* Text,
IN int Image);
/*
PURPOSE:
Called when an ASCII key is pressed.
NOTE:
Make sure you supercall the default implementation!
*/
virtual void OnIncrementalSearch(IN TCHAR ch);
/*
PURPOSE:
Called for each cell for determining its type
*/
virtual CellType OnGetCellType(IN int Row, IN int Col);
/*
PURPOSE:
Called for each cell in order to overwrite the global colors.
Additional information can be found in mDraw.
*/
virtual bool OnGetCellColors( IN int Row,
IN int Col,
OUT COLORREF& TextColor,
OUT COLORREF& BkColor,
OUT UINT8& TextStyle) const;
/*
PURPOSE:
Create in-place controls.
*/
virtual bool CreateInPlaceEdit(IN int Row, IN int Col, IN const RECT *CellRect);
virtual bool CreateInPlaceCombo(IN int Row, IN int Col, IN const RECT *CellRect, IN bool Editable);
/*
PURPOSE:
The DrawXxxCell routines handle cell painting.
*/
virtual void __fastcall DrawRegularCell();
virtual void __fastcall DrawEditBoxCell();
virtual void __fastcall DrawComboBoxCell();
virtual void __fastcall DrawCheckBoxCell();
virtual void __fastcall DrawCustomCell();
virtual void __fastcall DrawSeparatorCell();
protected:
bool mDestroying;
int mEditRow, mEditCol; // the cell that is currently beeing edited
int mRow, mCol; // the cell that has the focus
UINT16 mEditLen; // edit box text limit
TCHAR* mBuffer; // global buffer for handling strings
UINT16 mBufferLen;
bool mIncSearch;
CString mIncSearchString;
HWND mIncSearchTip;
UINT16 mIncSearchTimer;
protected:
struct TransientCustomDraw
{
NMLVCUSTOMDRAW* cd;
bool Focused;
bool Selected;
UINT8 Justify;
RECT Rect;
const TCHAR* CellText;
CellType Type;
int Icon;
bool GridLines;
HBITMAP ComboBmp;
HDC ComboDC;
HBITMAP CustomBmp;
HDC CustomDC;
HBITMAP CheckOnBmp;
HDC CheckOnDC;
HBITMAP CheckOffBmp;
HDC CheckOffDC;
bool UseDefaultColors;
HBRUSH BrushFrame;
COLORREF ColorFrame;
HBRUSH BrushNormalFill;
COLORREF ColorNormalFill;
HBRUSH BrushSelectedFill;
COLORREF ColorSelectedFill;
HBRUSH BrushButtonFill;
COLORREF ColorText;
COLORREF ColorSelText;
HFONT CustomFont;
UINT8 CustomFontStyle;
HBITMAP DefaultStockBmp;
bool Initialized;
void KillObjects()
{
if (!Initialized) return;
::DeleteObject(::SelectObject(ComboDC, DefaultStockBmp));
::DeleteDC(ComboDC);
::DeleteObject(::SelectObject(CustomDC, DefaultStockBmp));
::DeleteDC(CustomDC);
::DeleteObject(::SelectObject(CheckOnDC, DefaultStockBmp));
::DeleteDC(CheckOnDC);
::DeleteObject(::SelectObject(CheckOffDC, DefaultStockBmp));
::DeleteDC(CheckOffDC);
Initialized = false;
}
void KillBrushes()
{
::DeleteObject(BrushFrame);
::DeleteObject(BrushNormalFill);
::DeleteObject(BrushSelectedFill);
::DeleteObject(BrushButtonFill);
}
void SetColors( COLORREF ClFrame,
COLORREF ClNormalFill,
COLORREF ClSelFill,
COLORREF ClBtnFill,
COLORREF ClText,
COLORREF ClSelText)
{
// destroy previous brushes
if (!UseDefaultColors)
KillBrushes();
// new brushes
ColorFrame = ClFrame;
BrushFrame = ::CreateSolidBrush(ClFrame);
ColorNormalFill = ClNormalFill;
BrushNormalFill = ::CreateSolidBrush(ClNormalFill);
ColorSelectedFill = ClSelFill;
BrushSelectedFill = ::CreateSolidBrush(ClSelFill);
BrushButtonFill = ::CreateSolidBrush(ClBtnFill);
ColorText = ClText;
ColorSelText = ClSelText;
// mark custom colors flag
UseDefaultColors = false;
}
void ResetColors()
{
// destroy previous brushes
if (!UseDefaultColors)
KillBrushes();
// set to defaults
ColorFrame = ::GetSysColor(COLOR_BTNSHADOW);
BrushFrame = ::GetSysColorBrush(COLOR_BTNSHADOW);
ColorNormalFill = ::GetSysColor(COLOR_WINDOW);
BrushNormalFill = ::GetSysColorBrush(COLOR_WINDOW);
ColorSelectedFill = ::GetSysColor(COLOR_HIGHLIGHT);
BrushSelectedFill = ::GetSysColorBrush(COLOR_HIGHLIGHT);
BrushButtonFill = ::GetSysColorBrush(COLOR_BTNFACE);
ColorText = ::GetSysColor(COLOR_WINDOWTEXT);
ColorSelText = ::GetSysColor(COLOR_HIGHLIGHTTEXT);
}
TransientCustomDraw(): Initialized(false), UseDefaultColors(true), CustomFont(NULL), CustomFontStyle(0) { ResetColors(); };
~TransientCustomDraw()
{
if (!UseDefaultColors)
KillBrushes();
KillObjects();
if (CustomFont)
::DeleteObject(CustomFont);
}
};
// transient drawing info (valid beetween OnCustomDraw and DrawXxxCell(..) only!)
mutable TransientCustomDraw mDraw;
private:
/*
PURPOSE:
Handles NM_CUSTOMDRAW
*/
BOOL OnCustomDraw(IN NMHDR* Header, OUT LRESULT* Result);
/*
PURPOSE:
Generates a new font based on the current one, and caches it
within mDraw
ARGUMENTS:
Style Is a combination of 'enum FontStyle' values
*/
void GenerateFont(IN UINT8 Style);
private:
// window procs for in-place editors
static WNDPROC mOldChildProc, mOldComboEditProc, mOldComboListProc;
static HWND mComboLBox;
static bool mComboLBoxClicked;
static INT_PTR CALLBACK EditBoxProc(HWND, UINT, WPARAM, LPARAM);
static INT_PTR CALLBACK ComboBoxProc(HWND, UINT, WPARAM, LPARAM);
static INT_PTR CALLBACK ComboEditProc(HWND, UINT, WPARAM, LPARAM);
static INT_PTR CALLBACK ComboListProc(HWND, UINT, WPARAM, LPARAM);
};
#endif //CGRIDCTRL_H
//-------------------------------------------------------------------
// HISTORY
//-------------------------------------------------------------------
//
// $Log: CGridCtrl.h,v $
// Revision 1.10 2004/06/16 23:49:26 miezoo
// - vc6 compilable
//
// Revision 1.9 2004/06/16 18:20:58 miezoo
// - mouse related notifications
// - new events for button-ups
//
// Revision 1.8 2004/06/16 18:04:12 miezoo
// - AFX message handlers made virtual
//
// Revision 1.7 2004/06/14 08:10:01 miezoo
// - version [1.5]
//
// Revision 1.6 2004/06/09 17:00:51 miezoo
// - version [1.4]
// - separator cells
//
// Revision 1.5 2004/06/08 19:44:27 miezoo
// - version [1.3]
// - on-demand cell type
// - colors and font styles
// - USE_DEFAULT_ERASEBKGND vanished
//
// Revision 1.4 2004/06/06 23:13:03 miezoo
// - version [1.2]
// - comments
// - incremental search timer exposed
//
// Revision 1.3 2004/06/06 12:58:28 miezoo
// - version 1.1
// - private members exposed
//
// Revision 1.2 2004/06/06 12:07:20 miezoo
// - Version added
//
// Revision 1.1 2004/06/06 11:49:06 miezoo
// - Initial revision
//
//-------------------------------------------------------------------