#pragma once //_________________________________________________________________ //_________________________________________________________________ //___ QM_Grid ________________________________________________________________ //_________________________________________________________________ /* About QM_Grid control QM_Grid control is based on SysListView32 control. With it you can use SysListView32 messages, notifications and styles. All documented in the MSDN Library. QM_Grid allows user to edit cells. To edit a cell, it displays a temporary control. Use LVM_QG_SETCELLTYPE and/or LVM_QG_SETCOLUMNTYPE message to set control types and styles. Control types/styles: single-line edit (default), multiline edit, combo box, sorted combo box, check box (sets cell text to Yes or empty), date/time picker, and noneditable. Can be with a button. By default, all cells are editable, and user can easily add, delete and move rows. There are QM_Grid control styles that can be set using LVM_QG_SETSTYLE message: QG_NOEDITFIRSTCOLUMN does not allow user to edit cells in first column. QG_NOAUTOADD does not allow user to add, delete and move rows. QG_NOEDIT does not allow user to edit cells. A. Initializing (not necessary if you use Dialog Editor and ShowDialog). 1. Create control of QM_Grid class. Optionally use listview styles. 2. Optionally set listview extended styles and imagelists. 3. Optionally send LVM_QG_SETSTYLE. 4. Add columns (LVM_QG_ADDCOLUMNS or LVM_INSERTCOLUMN). 5. Optionally send LVM_QG_SETCOLUMNTYPE to set default cell type for columns (initially it is QG_EDIT). 6. Add items and subitems. Use one of: 1. LVM_INSERTITEM, LVM_SETITEMTEXT. It is the slowest. 2. LVM_QG_ADDROW. It can add or replace row. Can be specified range of cells in row. 3. LVM_QG_SETALLCELLS to set all from multistring. 4. ICsv.ToQmGrid. Internally uses LVM_QG_SETGETALL_CALLBACK. 5. LVM_QG_SETGETALL_CALLBACK to set all using callback function. 6. LVM_QG_SETGETALL_CSVSTRING to set all from CSV string. The 3-6 allow you to separately add first column and text of other columns: At first add items in first column. Use flag QG_SET_FIRST. Then set text of subitems. Use flag QG_SET_NOFIRST. 7. Optionally send LVM_QG_SETCELLTYPE to set styles of separate cells. B. Getting text from cells (not necessary if you use Dialog Editor and ShowDialog). Use one of: 1. LVM_GETITEMTEXT to get text from each cell you need. It is the slowest. 2. LVM_QG_GETROW to get text from all or range of cells in a row. 3. LVM_QG_GETALLCELLS to get all cells to a str variable in multistring format. 4. ICsv.FromQmGrid to get all to an ICsv variable. Internally uses LVM_QG_SETGETALL_CALLBACK. 5. LVM_QG_SETGETALL_CALLBACK to get all using callback function. 6. LVM_QG_SETGETALL_CSVSTRING to get all as CSV string. Notes With LVM_QG_SETALLCELLS and LVM_QG_GETALLCELLS, the str variable (whose address is passed as lParam) is in multistring format. That is, array of null-terminated strings that are in same memory location. Like "string1[0]string2[0]. To store such variable in registry, use REG_MULTI_SZ datatype. Multistring also is used with LVM_QG_ADDROW and LVM_QG_GETROW. A checkbox cell is checked if its text is "Yes". Columns can be added/deleted/typechanged only when the grid is empty. To do it later, at first delete all items. To delete all items, use LVM_DELETEALLITEMS. Don't use LVM_SETITEMCOUNT. C. Receiving notifications. You can optionally process LVN_ and LVN_QG_ notifications. You must process LVN_QG_BUTTONCLICK for cells that have QG_BUTTONATRIGHT style. For example, show a dialog and set edit control text. You must process LVN_QG_COMBOFILL for cells that have QG_COMBO type. Add combo box items. This message is sent each time before showing dropdown list. You optionally can process LVN_QG_COMBOITEMCLICK for cells that have QG_COMBO type. If you don't process it, or process but return 0, combo box edit control text is set to selected item's text. This message allows you to override this behavior. You for example can show a dialog, set edit control text, and return 1. You can process LVN_ENDLABELEDIT to validate user input. LVN_BEGINLABELEDIT - when user clicks an editable cell. LVN_QG_CHANGE - when user changes grid data (edits a cell, deleted a row, etc). The control does not send this notification when grid changes because of a message (LVM_INSERTITEM, LVM_SORTITEMSEX, etc). QM 2.4.2: also sent after cell editing, it text changed; then hctrl is 0. D. Mouse and keyboard navigation. Click editable cell to edit it. Click non-editable cell to select row. Click-drag at right or left to select rows. Also, you can Ctrl+Click or Shift+Click to select multiple rows. Right click or use App key to show context menu. If checkboxes style, Ctrl+click checkbox to toggle all; Shift+click to toggle children (following items with greater indent). In cell edit mode: Use Tab, Shift+Tab or arrows to edit next, prev, below or above. Use Enter to insert and edit new row. Use standard edit control navigation and context menu. Use Esc to deactivate cell edit mode. Not in cell edit mode: Use Down/Up arrows to select next/previous row. Use Spacebar to edit first editable cell of selected or first row. Enter and Esc will close the dialog. Other keys are given in the context menu. E. Using in exe. Take qmgrid.dll together with exe. To use the control not in a dialog, at first load the dll using LoadLibrary. F. QM 2.3.2. The list view control is virtual (LVS_OWNERDATA style). Virtual list view controls are faster and don't have cell text length limitation. Some list view control messages and other features don't work with virtual controls. It is documented in MSDN. However these messages work with QM_Grid: LVM_DELETEALLITEMS, LVM_DELETEITEM, LVM_INSERTITEM (only text, image, param, state and indent), LVM_SETITEMTEXT, LVM_GETITEMTEXT, LVM_SETITEM, LVM_GETITEM (only text, image, param, state and indent), LVM_SETITEMSTATE, LVM_GETITEMSTATE, LVM_SORTITEMS, LVM_SORTITEMSEX. Supports overlay images, state images and check boxes. Does not support subitem images and some other listview properties. You can set some other cell properties in LVN_GETDISPINFOW notification. QM_Grid also uses it. Changes in notification messages: Sends only Unicode messages, except LVN_BEGINLABELEDIT and LVN_ENDLABELEDIT (their text is in QM format, ie UTF-8 or ANSI, depending on QM Unicode mode). Does not send LVN_DELETEITEM and LVN_INSERTITEM when used deletes, moves, cuts or pastes rows. Just sends single LVN_QG_CHANGE message. Does not send LVN_DELETEITEM and LVN_DELETEALLITEMS at all. Several new LVM_QG_ messages, QM_Grid styles and control types. Cut/Copy/Paste rows. */ //////////////////////////////////////////////////// namespace _grid { //Public definitions enum ENUM_GRID_MESSAGES { //Messages LVM_QG_FIRST=(LVM_FIRST+240), //Sets grid style. //wParam - styles. Use values from enum ENUM_GRID_STYLES. //lParam - styles mask. //Returns 1 if successful, 0 if failed. LVM_QG_SETSTYLE=(LVM_QG_FIRST), //Sets control type, style, and other flags of specified cell. //wParam - row. //lParam - MAKELPARAM(column, flags). Use values from enum ENUM_GRID_CTYPE. //Returns 1 if successful, 0 if failed. LVM_QG_SETCELLTYPE=(LVM_QG_FIRST+1), //Sets default control type, style and flags for all cells of specified column. //wParam - column. //lParam - column default control type (use values from enum ENUM_GRID_CTYPE) and column flags (use values from enum ENUM_GRID_COLUMN_FLAGS). //Returns 1 if successful, 0 if failed. LVM_QG_SETCOLUMNTYPE=(LVM_QG_FIRST+2), //Sets all cells. //wParam - ENUM_GRID_SETGETALL flags. //lParam - address of a str variable containing multistring. //Returns 1 if successful, 0 if failed. LVM_QG_SETALLCELLS=(LVM_QG_FIRST+3), //Gets all cells. //wParam - ENUM_GRID_SETGETALL flags. //lParam - address of a str variable that receives multistring. //Returns number of cells if successful, 0 if failed. LVM_QG_GETALLCELLS=(LVM_QG_FIRST+4), //Gets various grid info. //Low-order word of wParam specifies what info to get. A value from enum ENUM_GRID_INFO. //QG_GETINFO_STYLE (0) - return grid style, as set by LVM_QG_SETSTYLE. //QG_GETINFO_ROWCOLUMNCOUNT (1) - return row count. If lParam is int*, stores columns count there. lParam can be 0. //QG_GETINFO_COLUMNTYPE (2) - return column default control type, as set by LVM_QG_SETCOLUMNTYPE. lParam is column index. //QG_GETINFO_CELLTYPE (3) - return cell control type, as set by LVM_QG_SETCELLTYPE. High-order word of wParam is column index. lParam is row index. //QG_GETINFO_ISCHANGED (4) - return 1 if grid content is modified by the user (cells edited, rows added, etc). lParam is flags: 1 reset the "changed" state, 2 set the "changed" state. LVM_QG_GETINFO=(LVM_QG_FIRST+5), //Adds columns, sets column widths and default control types. //wParam - flags: //QG_AC_SB (1) - when calculating width %, assume there will be vertical scrollbar. //QG_AC_SETOPT (2) - first row sets grid options, like when creating control. The whole CSV is like in dialog definition. //lParam - CSV-formatted string where each row defines grid column. //The CSV can contain 1 to 4 columns, separated by comma. //1 - grid column text. //2 - grid column width. Can be percent, like 25%. //3 - default control type of the column. Use values from enum ENUM_GRID_CTYPE. It must be simple numeric value, not constant name. //4 - column flags. Use values from enum ENUM_GRID_COLUMN_FLAGS. It must be simple numeric value, not constant name. //Returns 1 if successful, 0 if failed. //Fails if the grid contains rows. If contains columns, deletes. LVM_QG_ADDCOLUMNS=(LVM_QG_FIRST+6), //Adds or replaces row. //wParam - row index. //lParam - QG_ROW*. //Returns row index if successful, -1 if failed. //If row index <0, adds new row to the end. If > row count, adds empty rows before. //If the row exists: if flag 4 is set, replaces row text (only the specified cells), else inserts new row. //When adding many items, this message is much faster than LVM_INSERTITEM/LVM_SETITEM. But you should not send other messages between LVM_QG_ADDROW. //This message removes selection. LVM_QG_ADDROW=(LVM_QG_FIRST+7), //Gets row cells in multistring format. //wParam - row index. //lParam - QG_ROW*. //Returns number of bytes in the multistring. //Returns -1 if succeeds but nCells is 0. //If flag 2, returns -2 if succeeds but all the cells are empty. //If flag 4, returns -4 if succeeds but the row is not selected or not checked (if QG_CHECKBOXES style). LVM_QG_GETROW=(LVM_QG_FIRST+8), //Sets or gets all cells using callback function. //Used by ICsv FromQmGrid and ToQmGrid. //lParam - QG_SGACB*. //Returns 1 if successful, 0 if failed. //ENUM_GRID_SETGETALL flags can be set when creating control, in text. LVM_QG_SETGETALL_CALLBACK=(LVM_QG_FIRST+9), //Sets or gets all cells as CSV string. //wParam - flags: 1 set, 0 get. //lParam - if set, LPSTR, else str*. //Returns 1 if successful, 0 if failed. //ENUM_GRID_SETGETALL flags can be set when creating control, in text. Always uses comma as separator. LVM_QG_SETGETALL_CSVSTRING=(LVM_QG_FIRST+10), //Sorts. //wParam - flags: 0 simple, 1 insens, 2 ling, 3 ling/insens, 4 numbers/ling/insens, 128 date, 0x100 descending, 0x10000 toggle, 0x20000 just set image //lParam - column. //Returns 1 if successful, 0 if failed. LVM_QG_SORT=(LVM_QG_FIRST+11), //Sets button icon and/or tooltip. //wParam - icon handle. The control does not copy the icon, therefore it must be alive for a while. If 1, uses standard "open folder" icon. //lParam - tooltip text. //Returns 1 if successful, 0 if failed. //Can be called only when received LVN_BEGINLABELEDIT notification. Applies only to that button instance. LVM_QG_SETBUTTONPROP=(LVM_QG_FIRST+12), //Notifications LVN_QG_FIRST=(LVN_LAST), LVN_QG_BUTTONCLICK=(LVN_QG_FIRST), //must return 0 LVN_QG_COMBOFILL=(LVN_QG_FIRST+1), //must return 0 LVN_QG_COMBOITEMCLICK=(LVN_QG_FIRST+2), //must return 0, or 1 to preserve edit control text LVN_QG_CHANGE=(LVN_QG_FIRST+3), //must return 0 }; //Also, QM_Grid changes these SysListView32 messages and notifications: //LVM_EDITLABEL - lParam is subitem index. //LVN_BEGINLABELEDIT - LVITEM::iSubItem is valid. //LVN_ENDLABELEDIT - LVITEM::iSubItem is valid. Return 1 to leave old text. //Also, QM_Grid can be initialized when creating. Dialog Editor inserts code for it in dialog definition. //Let text be CSV string. First row sets grid options. Other rows add columns as with LVM_QG_ADDCOLUMNS. //First row cells: //grid style, //LVM_QG_ADDCOLUMNS flags, //LVM_QG_SETGETALL_CSVSTRING set flags, //LVM_QG_SETGETALL_CSVSTRING get flags. //list view extended styles to add. //When creating the control, it adds these styles: LVS_REPORT|LVS_OWNERDATA|LVS_SHAREIMAGELISTS|WS_CLIPCHILDREN. //And these list view extended styles: LVS_EX_GRIDLINES|LVS_EX_FULLROWSELECT|LVS_EX_INFOTIP. //And calls LVM_SETCALLBACKMASK to set LVIS_STATEIMAGEMASK|LVIS_OVERLAYMASK. //LVM_QG_GETINFO wParam enum ENUM_GRID_INFO { QG_GETINFO_STYLE, QG_GETINFO_ROWCOLUMNCOUNT, QG_GETINFO_COLUMNTYPE, QG_GETINFO_CELLTYPE, QG_GETINFO_ISCHANGED, }; enum ENUM_GRID_WHATCHANGED { QG_CHANGED_INSERT=1, //added row QG_CHANGED_CELL=2, //ended cell editing (sent only if text changed), or checked/unchecked; then hctrl is 0, txt is new text. QG_CHANGED_CELLTEXT=3, //sent while in cell edit mode, on each typed character etc; then hctrl is control with new text, txt is old text. QG_CHANGED_DELETE=4, //row(s) deleted QG_CHANGED_MOVE=5, //row(s) moved (up/down or drag/drop) QG_CHANGED_CUT=6, QG_CHANGED_PASTEINSERT=7, QG_CHANGED_PASTEREPLACE=8, }; //This struct is sent with each LVN_QG_ notification (some members are used only with certain notifications): struct QM_NMLVDATA { NMHDR hdr; HWND hctrl, hcb; int ctrltype, item, subitem, cbindex; LPSTR txt; int whatChanged; }; //hdr - notification code, grid control handle and id. //hctrl - edit control (not grid control) handle. Used with LVN_QG_CHANGE, when whatChanged is QG_CHANGED_CELLTEXT, else 0. //hcb - combo box control handle. //ctrltype - cell control type from ENUM_GRID_CTYPE. //item and subitem - specifies the cell, or -1 if not used with that notification. //cbindex - on LVN_QG_COMBOITEMCLICK it is index of selected combo box item, else -1. //txt - current cell text (not edit control text). Used with LVN_QG_CHANGE, when whatChanged is QG_CHANGED_CELLTEXT or QG_CHANGED_CELL. //whatChanged (QM 2.4.2) - used with LVN_QG_CHANGE, else 0. See enum ENUM_GRID_WHATCHANGED. //This struct is passed to LVM_QG_ADDROW and LVM_QG_GETROW as lParam. wParam is row index. struct QG_ROW { void* cells; int firstCell, nCells; DWORD flags; LVITEM* lvi; }; //cells - row cells. //With LVM_QG_ADDROW, caller sets it. //With LVM_QG_GETROW, QM_Grid sets it as temporary multistring. If the message returns a negative value, cells will be "". //firstCell - set/get starting from this column. //nCells - set/get this number of cells. Fails if firstCell+nCells is more than grid column count. //flags with LVM_QG_ADDROW: 0 - cells is multistring, 1 - cells is LPSTR*, 2 - cells is str*, 4 - replace, 8 - apply options when replace. //flags with LVM_QG_GETROW: 2 - return -2 if all the cells are empty, 4 - return -4 if the row is not selected or not checked (if QG_CHECKBOXES style). //lvi - can be used to set images, lparam and indent. Optional. //This struct is used internally with LVM_QG_SETGETALL_CALLBACK. typedef HRESULT (__stdcall* ftQmGridCallback)(void* p); //called by qmgrid for each row struct QG_SGACB { void* param; ftQmGridCallback func; bool set; DWORD flags; //fills caller. flags is from enum ENUM_GRID_SETGETALL. DWORD nrows, ncols; //on set, fills caller. On get, fills qmgrid. DWORD row, col; //fills qmgrid LPSTR cells; //on set, fills the callback func. On get, fills qmgrid. }; //QM_Grid control styles enum ENUM_GRID_STYLES { QG_NOEDITFIRSTCOLUMN=1, //first column is read-only, no matter what control types are set QG_NOAUTOADD=2, //user cannot add, delete or move rows //QG_SETROWTYPE - when you set control type of the first cell in a row, it sets control type for all cells in the row. //Also, when adding a row, you can specify row control type and/or other row properties in first cell's text. //Syntax: text //ctype - row control type (a value from enum ENUM_GRID_CTYPE). //lparam - an user-defined int value. //image - image index. If negative, will be without image. //overlayImage - overlay image index. Valid values are 1 to 15. //Index 0 will not add overlay image. //Overlay images are drawn over normal images. //To define overlay images, call ImageList_SetOverlayImage. //stateImage - state image index. Valid values are 1 to 15. //The index is 1-based, therefore index 1 will display image 0 from imagelist. Index 0 will not add state image. //State images are drawn in the space reserved to the left from normal images. //State imagelist must be set (LVM_SETIMAGELIST with LVSIL_STATE), or LVS_EX_CHECKBOXES style must be set with LVM_SETEXTENDEDLISTVIEWSTYLE. //indent - indent. It is number of image widths. Valid values are -1 to 254. //ctypes - list of cell control types. Use . to inherit from ctype or column. Use -1 to inherit from column. Example: .0 -1..2 //The parameters are optional. For example, can be text, or text. //The parameters must be simple numbers. //To display images and indent, imagelist must be set (LVM_SETIMAGELIST with LVSIL_SMALL). //All except ctype and ctypes also can be set/retrieved using LVM_SETITEM/LVM_GETITEM. //If style QG_NOEDITFIRSTCOLUMN also is set, will not remove the <...> string. Just will not display it. See also QG_GET_NOROWTYPE. QG_SETROWTYPE=4, //QG_AUTONUMBER - in first column display row numbers. //The cells can contain any text, but it is not displayed and cannot be retrieved using list view control messages (only LVM_QG_ messages retrieve it). //Also, when adding items with LVM_QG_SETALLCELLS or LVM_QG_SETGETALL_CALLBACK, always at first deletes all rows, regardless of flags. QG_AUTONUMBER=8, QG_NOEDIT=16, //don't allow user to edit cells. //QG_CHECKBOXES - adds list view extended style LVS_EX_CHECKBOXES. //Also, when getting text, if flag QG_GET_SELECTED, gets only checked items. //Also, if LVS_EX_BORDERSELECT, checks/unchecks when clicked in any non-editable area of the row. //Sends LVN_ITEMCHANGED notification only on click, and not when checked/unchecked using functions or messages. QG_CHECKBOXES=32, //QG_EDITSELECTED (QM 2.4.0) - on left button down, begin edit mode only if the row is selected and focused. Else select/focus. QG_EDITIFSELECTED=64, //QG_DRAGDROP (QM 2.4.2) - user can drag and drop rows. //To drag and drop, begin in the first column. To select rows, begin in another column. QG_DRAGDROP=128, //QG_TREE (QM 2.4.2) - assume that rows in the grid are indented to display a tree. //On move up/down or drag&drop rows, corrects indentation of moved rows to match indentation of new sibling rows. //If QG_SETROWTYPE, copies/pastes rows with indentations, even if no QG_GETEX_INDENT. QG_TREE=0x100, }; //control styles and flags enum ENUM_GRID_CTYPE { QG_EDIT=0, QG_COMBO=1, QG_CHECK=2, QG_DATETIME=3, QG_NONE=7, QG_CONTROLTYPEMASK=7, //control type QG_EDIT_MULTILINE=8, QG_COMBO_SORT=8, QG_DATETIME_TIME=8, //control style QG_BUTTONATRIGHT=16, //other flags }; //flags for LVM_QG_SETALLCELLS, LVM_QG_GETALLCELLS, LVM_QG_SETGETALL_CALLBACK and LVM_QG_SETGETALL_CSVSTRING (set when creating control, in text) enum ENUM_GRID_SETGETALL { QG_GET_NOFIRST=1, QG_GET_NOEMPTYLINES=2, QG_GET_SELECTED=4, QG_GET_NOROWTYPE=8, //get QG_GETEX_CTYPE=0x10000, QG_GETEX_LPARAM=0x20000, QG_GETEX_IMAGE=0x40000, QG_GETEX_OVERLAYIMAGE=0x80000, QG_GETEX_STATEIMAGE=0x100000, QG_GETEX_INDENT=0x200000, QG_GETEX_CTYPES=0x400000, QG_GETEX_MASK=0x7F0000, //get (QM 2.4.2) QG_SET_FIRST=1, QG_SET_NOFIRST=2, //set }; //flags for LVM_QG_ADDCOLUMNS enum ENUM_GRID_ADDCOLUMNS { QG_AC_SB=1, //assume vert scrollbar QG_AC_SETOPT=2, //first row sets grid options, like when creating control. The whole CSV is like in dialog definition. }; //column flags enum ENUM_GRID_COLUMN_FLAGS { QG_CF_CTYPE_PRIORITY=1, //setting row type does not overwrite column type }; //Functions. //Currently there are no exported functions. //The dll registers QM_Grid class when you load it (LoadLibrary). #ifdef QMGRID_EXPORTS #define EXPORT_QMGRID extern "C" __declspec(dllexport) #else #define EXPORT_QMGRID extern "C" __declspec(dllimport) #endif } //namespace _grid using namespace _grid;