Mercurial > projects > dwt-win
diff dwt/widgets/Table.d @ 213:36f5cb12e1a2
Update to SWT 3.4M7
author | Frank Benoit <benoit@tionex.de> |
---|---|
date | Sat, 17 May 2008 17:34:28 +0200 |
parents | ab60f3309436 |
children | a8fed3e56433 |
line wrap: on
line diff
--- a/dwt/widgets/Table.d Mon May 05 00:12:38 2008 +0200 +++ b/dwt/widgets/Table.d Sat May 17 17:34:28 2008 +0200 @@ -33,6 +33,7 @@ import dwt.widgets.Event; import dwt.widgets.Control; import dwt.widgets.Display; +import dwt.widgets.Shell; import dwt.dwthelper.utils; @@ -66,12 +67,13 @@ * </pre></code> * </p><p> * Note that although this class is a subclass of <code>Composite</code>, - * it does not make sense to add <code>Control</code> children to it, - * or set a layout on it. + * it does not normally make sense to add <code>Control</code> children to + * it, or set a layout on it, unless implementing something like a cell + * editor. * </p><p> * <dl> * <dt><b>Styles:</b></dt> - * <dd>SINGLE, MULTI, CHECK, FULL_SELECTION, HIDE_SELECTION, VIRTUAL</dd> + * <dd>SINGLE, MULTI, CHECK, FULL_SELECTION, HIDE_SELECTION, VIRTUAL, NO_SCROLL</dd> * <dt><b>Events:</b></dt> * <dd>Selection, DefaultSelection, SetData, MeasureItem, EraseItem, PaintItem</dd> * </dl> @@ -96,10 +98,11 @@ ImageList imageList, headerImageList; TableItem currentItem; TableColumn sortColumn; + RECT* focusRect; + HWND headerToolTipHandle; bool ignoreCustomDraw, ignoreDrawForeground, ignoreDrawBackground, ignoreDrawFocus, ignoreDrawSelection, ignoreDrawHot; bool customDraw, dragStarted, explorerTheme, firstColumnImage, fixScrollWidth, tipRequested, wasSelected, wasResized; - bool ignoreActivate, ignoreSelect, ignoreShrink, ignoreResize, ignoreColumnMove, ignoreColumnResize; - HWND headerToolTipHandle; + bool ignoreActivate, ignoreSelect, ignoreShrink, ignoreResize, ignoreColumnMove, ignoreColumnResize, fullRowSelect; int itemHeight, lastIndexOf, lastWidth, sortDirection, resizeCount, selectionForeground, hotIndex; static /*final*/ WNDPROC HeaderProc; static const int INSET = 4; @@ -109,6 +112,8 @@ static const int HEADER_EXTRA = 3; static const int VISTA_EXTRA = 2; static const int EXPLORER_EXTRA = 2; + static final int H_SCROLL_LIMIT = 32; + static final int V_SCROLL_LIMIT = 16; static const bool EXPLORER_THEME = true; private static /+const+/ WNDPROC TableProc; static const TCHAR[] TableClass = OS.WC_LISTVIEW; @@ -159,6 +164,7 @@ * @see DWT#FULL_SELECTION * @see DWT#HIDE_SELECTION * @see DWT#VIRTUAL + * @see DWT#NO_SCROLL * @see Widget#checkSubclass * @see Widget#getStyle */ @@ -176,8 +182,7 @@ setCustomDraw (true); setBackgroundTransparent (true); if (OS.COMCTL32_MAJOR < 6) style |= DWT.DOUBLE_BUFFERED; - //TODO - LVS_EX_LABELTIP causes white rectangles (turn it off) - OS.SendMessage (handle, OS.LVM_SETEXTENDEDLISTVIEWSTYLE, OS.LVS_EX_LABELTIP, 0); + if (OS.IsWinCE) OS.SendMessage (handle, OS.LVM_SETEXTENDEDLISTVIEWSTYLE, OS.LVS_EX_LABELTIP, 0); break; default: } @@ -263,7 +268,16 @@ /* Resize messages */ case OS.WM_WINDOWPOSCHANGED: redraw = findImageControl () !is null && drawCount is 0 && OS.IsWindowVisible (handle); - if (redraw) OS.DefWindowProc (handle, OS.WM_SETREDRAW, 0, 0); + if (redraw) { + /* + * Feature in Windows. When LVM_SETBKCOLOR is used with CLR_NONE + * to make the background of the table transparent, drawing becomes + * slow. The fix is to temporarily clear CLR_NONE when redraw is + * turned off. + */ + OS.DefWindowProc (handle, OS.WM_SETREDRAW, 0, 0); + OS.SendMessage (handle, OS.LVM_SETBKCOLOR, 0, 0xFFFFFF); + } //FALL THROUGH /* Mouse messages */ @@ -298,7 +312,66 @@ bool oldSelected = wasSelected; if (checkSelection) wasSelected = false; if (checkActivate) ignoreActivate = true; - int code = OS.CallWindowProc (TableProc, hwnd, msg, wParam, lParam); + + /* + * Bug in Windows. For some reason, when the WS_EX_COMPOSITED + * style is set in a parent of a table and the header is visible, + * Windows issues an endless stream of WM_PAINT messages. The + * fix is to call BeginPaint() and EndPaint() outside of WM_PAINT + * and pass the paint HDC in to the window proc. + */ + bool fixPaint = false; + if (msg is OS.WM_PAINT) { + int bits0 = OS.GetWindowLong (handle, OS.GWL_STYLE); + if ((bits0 & OS.LVS_NOCOLUMNHEADER) is 0) { + HWND hwndParent = OS.GetParent (handle), hwndOwner = null; + while (hwndParent !is null) { + int bits1 = OS.GetWindowLong (hwndParent, OS.GWL_EXSTYLE); + if ((bits1 & OS.WS_EX_COMPOSITED) !is 0) { + fixPaint = true; + break; + } + hwndOwner = OS.GetWindow (hwndParent, OS.GW_OWNER); + if (hwndOwner !is null) break; + hwndParent = OS.GetParent (hwndParent); + } + } + } + + /* Remove the scroll bars that Windows keeps automatically adding */ + bool fixScroll = false; + if ((style & DWT.H_SCROLL) is 0 || (style & DWT.V_SCROLL) is 0) { + switch (msg) { + case OS.WM_PAINT: + case OS.WM_NCPAINT: + case OS.WM_WINDOWPOSCHANGING: { + int bits = OS.GetWindowLong (hwnd, OS.GWL_STYLE); + if ((style & DWT.H_SCROLL) is 0 && (bits & OS.WS_HSCROLL) !is 0) { + fixScroll = true; + bits &= ~OS.WS_HSCROLL; + } + if ((style & DWT.V_SCROLL) is 0 && (bits & OS.WS_VSCROLL) !is 0) { + fixScroll = true; + bits &= ~OS.WS_VSCROLL; + } + if (fixScroll) OS.SetWindowLong (handle, OS.GWL_STYLE, bits); + } + } + } + int /*long*/ code = 0; + if (fixPaint) { + PAINTSTRUCT ps; + auto hDC = OS.BeginPaint (hwnd, &ps); + code = TableProc( hwnd, OS.WM_PAINT, cast(int)hDC, lParam); + OS.EndPaint (hwnd, &ps); + } else { + code = TableProc( hwnd, msg, wParam, lParam); + } + if (fixScroll) { + int flags = OS.RDW_FRAME | OS.RDW_INVALIDATE; + OS.RedrawWindow (handle, null, null, flags); + } + if (checkActivate) ignoreActivate = false; if (checkSelection) { if (wasSelected || forceSelect) { @@ -328,6 +401,7 @@ /* Resize messages */ case OS.WM_WINDOWPOSCHANGED: if (redraw) { + OS.SendMessage (handle, OS.LVM_SETBKCOLOR, 0, OS.CLR_NONE); OS.DefWindowProc (handle, OS.WM_SETREDRAW, 1, 0); OS.InvalidateRect (handle, null, true); auto hwndHeader = cast(HWND) OS.SendMessage (handle, OS.LVM_GETHEADER, 0, 0); @@ -370,13 +444,17 @@ static int checkStyle (int style) { /* - * Feature in Windows. It is not possible to create - * a table that does not have scroll bars. Therefore, - * no matter what style bits are specified, set the - * H_SCROLL and V_SCROLL bits so that the DWT style - * will match the widget that Windows creates. + * Feature in Windows. Even when WS_HSCROLL or + * WS_VSCROLL is not specified, Windows creates + * trees and tables with scroll bars. The fix + * is to set H_SCROLL and V_SCROLL. + * + * NOTE: This code appears on all platforms so that + * applications have consistent scroll bar behavior. */ - style |= DWT.H_SCROLL | DWT.V_SCROLL; + if ((style & DWT.NO_SCROLL) is 0) { + style |= DWT.H_SCROLL | DWT.V_SCROLL; + } return checkBits (style, DWT.SINGLE, DWT.MULTI, 0, 0, 0, 0); } @@ -497,6 +575,13 @@ int dwExStyle = OS.SendMessage (handle, OS.LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0); if ((dwExStyle & OS.LVS_EX_FULLROWSELECT) is 0) { int bits = OS.LVS_EX_FULLROWSELECT; + /* + * Feature in Windows. When LVM_SETEXTENDEDLISTVIEWSTYLE is + * used to set or clear the extended style bits and the table + * has a tooltip, the tooltip is hidden. The fix is to clear + * the tooltip before setting the bits and then reset it. + */ + int /*long*/ hwndToolTip = OS.SendMessage (handle, OS.LVM_SETTOOLTIPS, 0, 0); static if (OS.IsWinCE) { RECT rect; bool damaged = cast(bool) OS.GetUpdateRect (handle, &rect, true); @@ -511,6 +596,12 @@ if (result !is OS.NULLREGION) OS.InvalidateRgn (handle, rgn, true); OS.DeleteObject (rgn); } + /* + * Bug in Windows. Despite the documentation, LVM_SETTOOLTIPS + * uses WPARAM instead of LPARAM for the new tooltip The fix + * is to put the tooltip in both parameters. + */ + hwndToolTip = OS.SendMessage (handle, OS.LVM_SETTOOLTIPS, hwndToolTip, hwndToolTip); } } } @@ -536,6 +627,13 @@ int dwExStyle = OS.SendMessage (handle, OS.LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0); if ((dwExStyle & OS.LVS_EX_FULLROWSELECT) !is 0) { int bits = OS.LVS_EX_FULLROWSELECT; + /* + * Feature in Windows. When LVM_SETEXTENDEDLISTVIEWSTYLE is + * used to set or clear the extended style bits and the table + * has a tooltip, the tooltip is hidden. The fix is to clear + * the tooltip before setting the bits and then reset it. + */ + auto hwndToolTip = OS.SendMessage (handle, OS.LVM_SETTOOLTIPS, 0, 0); static if (OS.IsWinCE) { RECT rect; bool damaged = cast(bool) OS.GetUpdateRect (handle, &rect, true); @@ -550,6 +648,12 @@ if (result !is OS.NULLREGION) OS.InvalidateRgn (handle, rgn, true); OS.DeleteObject (rgn); } + /* + * Bug in Windows. Despite the documentation, LVM_SETTOOLTIPS + * uses WPARAM instead of LPARAM for the new tooltip The fix + * is to put the tooltip in both parameters. + */ + hwndToolTip = OS.SendMessage (handle, OS.LVM_SETTOOLTIPS, hwndToolTip, hwndToolTip); } } } @@ -653,6 +757,12 @@ sendPaintItemEvent (item, nmcd); //widget could be disposed at this point } + if (!ignoreDrawFocus && focusRect !is null) { + OS.SetTextColor (nmcd.nmcd.hdc, 0); + OS.SetBkColor (nmcd.nmcd.hdc, 0xFFFFFF); + OS.DrawFocusRect (nmcd.nmcd.hdc, focusRect); + focusRect = null; + } } return null; } @@ -672,8 +782,7 @@ */ TableItem item = _getItem (nmcd.nmcd.dwItemSpec); if (item is null) return null; - HFONT hFont = item.cellFont !is null ? item.cellFont [nmcd.iSubItem] : cast(HFONT)-1; - if (hFont is cast(HFONT)-1) hFont = item.font; + HFONT hFont = item.fontHandle (nmcd.iSubItem); if (hFont !is cast(HFONT)-1) OS.SelectObject (hDC, hFont); if (ignoreCustomDraw || (nmcd.nmcd.rc.left is nmcd.nmcd.rc.right)) { return new LRESULT (hFont is cast(HFONT)-1 ? OS.CDRF_DODEFAULT : OS.CDRF_NEWFONT); @@ -682,12 +791,13 @@ selectionForeground = -1; ignoreDrawForeground = ignoreDrawSelection = ignoreDrawFocus = ignoreDrawBackground = false; if (OS.IsWindowVisible (handle)) { + Event measureEvent = null; if (hooks (DWT.MeasureItem)) { - sendMeasureItemEvent (item, nmcd.nmcd.dwItemSpec, nmcd.iSubItem, nmcd.nmcd.hdc); + measureEvent = sendMeasureItemEvent (item, nmcd.nmcd.dwItemSpec, nmcd.iSubItem, nmcd.nmcd.hdc); if (isDisposed () || item.isDisposed ()) return null; } if (hooks (DWT.EraseItem)) { - sendEraseItemEvent (item, nmcd, lParam); + sendEraseItemEvent (item, nmcd, lParam, measureEvent); if (isDisposed () || item.isDisposed ()) return null; code |= OS.CDRF_NOTIFYPOSTPAINT; } @@ -723,7 +833,7 @@ if ((result !is 0 && (lvItem.state & OS.LVIS_SELECTED) !is 0)) { int clrSelection = -1; if (nmcd.iSubItem is 0) { - if (OS.GetFocus () is handle) { + if (OS.GetFocus () is handle || display.getHighContrast ()) { clrSelection = OS.GetSysColor (OS.COLOR_HIGHLIGHT); } else { if ((style & DWT.HIDE_SELECTION) is 0) { @@ -731,7 +841,7 @@ } } } else { - if (OS.GetFocus () is handle) { + if (OS.GetFocus () is handle || display.getHighContrast ()) { clrText = OS.GetSysColor (OS.COLOR_HIGHLIGHTTEXT); clrTextBk = clrSelection = OS.GetSysColor (OS.COLOR_HIGHLIGHT); } else { @@ -1172,11 +1282,11 @@ } bits |= width & 0xFFFF; } - int result = OS.SendMessage (handle, OS.LVM_APPROXIMATEVIEWRECT, -1, bits | 0xFFFF0000); - int width = result & 0xFFFF; - int empty = OS.SendMessage (handle, OS.LVM_APPROXIMATEVIEWRECT, 0, 0); - int oneItem = OS.SendMessage (handle, OS.LVM_APPROXIMATEVIEWRECT, 1, 0); - int itemHeight = (oneItem >> 16) - (empty >> 16); + int /*long*/ result = OS.SendMessage (handle, OS.LVM_APPROXIMATEVIEWRECT, -1, OS.MAKELPARAM (bits, 0xFFFF)); + int width = OS.LOWORD (result); + int /*long*/ empty = OS.SendMessage (handle, OS.LVM_APPROXIMATEVIEWRECT, 0, 0); + int /*long*/ oneItem = OS.SendMessage (handle, OS.LVM_APPROXIMATEVIEWRECT, 1, 0); + int itemHeight = OS.HIWORD (oneItem) - OS.HIWORD (empty); height += OS.SendMessage (handle, OS.LVM_GETITEMCOUNT, 0, 0) * itemHeight; if (width is 0) width = DEFAULT_WIDTH; if (height is 0) height = DEFAULT_HEIGHT; @@ -1199,7 +1309,7 @@ /* Use the Explorer theme */ if (EXPLORER_THEME) { - if (!OS.IsWinCE && OS.WIN32_VERSION >= OS.VERSION (6, 0)) { + if (!OS.IsWinCE && OS.WIN32_VERSION >= OS.VERSION (6, 0) && OS.IsAppThemed ()) { explorerTheme = true; OS.SetWindowTheme (handle, Display.EXPLORER.ptr, null); } @@ -1208,7 +1318,7 @@ /* Get the header window proc */ if (HeaderProc is null) { auto hwndHeader = cast(HWND) OS.SendMessage (handle, OS.LVM_GETHEADER, 0, 0); - HeaderProc = cast(WNDPROC) OS.GetWindowLong (hwndHeader, OS.GWL_WNDPROC); + HeaderProc = cast(WNDPROC) OS.GetWindowLongPtr (hwndHeader, OS.GWLP_WNDPROC); } /* @@ -1237,9 +1347,9 @@ /* Set the checkbox image list */ if ((style & DWT.CHECK) !is 0) { - int empty = OS.SendMessage (handle, OS.LVM_APPROXIMATEVIEWRECT, 0, 0); - int oneItem = OS.SendMessage (handle, OS.LVM_APPROXIMATEVIEWRECT, 1, 0); - int width = (oneItem >> 16) - (empty >> 16), height = width; + int /*long*/ empty = OS.SendMessage (handle, OS.LVM_APPROXIMATEVIEWRECT, 0, 0); + int /*long*/ oneItem = OS.SendMessage (handle, OS.LVM_APPROXIMATEVIEWRECT, 1, 0); + int width = OS.HIWORD (oneItem) - OS.HIWORD (empty), height = width; setCheckboxImageList (width, height, false); OS.SendMessage (handle, OS. LVM_SETCALLBACKMASK, OS.LVIS_STATEIMAGEMASK, 0); } @@ -1290,22 +1400,30 @@ * * NOTE: WS_EX_LAYOUTRTL is not supported on Windows NT. */ - if (OS.WIN32_VERSION < OS.VERSION (4, 10)) return; - if ((style & DWT.RIGHT_TO_LEFT) !is 0) { - auto hwndHeader = cast(HWND) OS.SendMessage (handle, OS.LVM_GETHEADER, 0, 0); - int bits2 = OS.GetWindowLong (hwndHeader, OS.GWL_EXSTYLE); - OS.SetWindowLong (hwndHeader, OS.GWL_EXSTYLE, bits2 | OS.WS_EX_LAYOUTRTL); + if (OS.WIN32_VERSION >= OS.VERSION (4, 10)) { + if ((style & DWT.RIGHT_TO_LEFT) !is 0) { + auto hwndHeader = cast(HWND) OS.SendMessage (handle, OS.LVM_GETHEADER, 0, 0); + int bits2 = OS.GetWindowLong (hwndHeader, OS.GWL_EXSTYLE); + OS.SetWindowLong (hwndHeader, OS.GWL_EXSTYLE, bits2 | OS.WS_EX_LAYOUTRTL); + auto hwndTooltop = cast(HWND)OS.SendMessage (handle, OS.LVM_GETTOOLTIPS, 0, 0); + int bits3 = OS.GetWindowLong (hwndTooltop, OS.GWL_EXSTYLE); + OS.SetWindowLong (hwndTooltop, OS.GWL_EXSTYLE, bits3 | OS.WS_EX_LAYOUTRTL); + } } } void createHeaderToolTips () { static if (OS.IsWinCE) return; if (headerToolTipHandle !is null) return; + int bits = 0; + if (OS.WIN32_VERSION >= OS.VERSION (4, 10)) { + if ((style & DWT.RIGHT_TO_LEFT) !is 0) bits |= OS.WS_EX_LAYOUTRTL; + } headerToolTipHandle = OS.CreateWindowEx ( - 0, + bits, OS.TOOLTIPS_CLASS.ptr, null, - 0, + OS.TTS_NOPREFIX, OS.CW_USEDEFAULT, 0, OS.CW_USEDEFAULT, 0, handle, null, @@ -1382,11 +1500,10 @@ item.cellForeground = temp; } if (item.cellFont !is null) { - auto cellFont = item.cellFont; - HFONT[] temp = new HFONT[]( columnCount + 1 ); + Font [] cellFont = item.cellFont; + Font [] temp = new Font [columnCount + 1]; System.arraycopy (cellFont, 0, temp, 0, index); System.arraycopy (cellFont, index, temp, index + 1, columnCount - index); - temp [index] = cast(HFONT)-1; item.cellFont = temp; } } @@ -1435,7 +1552,18 @@ } else { OS.SendMessage (handle, OS.LVM_SETCOLUMNWIDTH, 0, 0); } - if ((parent.style & DWT.VIRTUAL) is 0) { + /* + * Bug in Windows. Despite the fact that every item in the + * table always has LPSTR_TEXTCALLBACK, Windows caches the + * bounds for the selected items. This means that + * when you change the string to be something else, Windows + * correctly asks you for the new string but when the item + * is selected, the selection draws using the bounds of the + * previous item. The fix is to reset LPSTR_TEXTCALLBACK + * even though it has not changed, causing Windows to flush + * cached bounds. + */ + if ((style & DWT.VIRTUAL) is 0) { LVITEM lvItem; lvItem.mask = OS.LVIF_TEXT | OS.LVIF_IMAGE; lvItem.pszText = OS.LPSTR_TEXTCALLBACK; @@ -1713,7 +1841,18 @@ OS.SendMessage (hwndHeader, OS.HDM_SETITEM, index, &hdItem); } } - if ((parent.style & DWT.VIRTUAL) is 0) { + /* + * Bug in Windows. Despite the fact that every item in the + * table always has LPSTR_TEXTCALLBACK, Windows caches the + * bounds for the selected items. This means that + * when you change the string to be something else, Windows + * correctly asks you for the new string but when the item + * is selected, the selection draws using the bounds of the + * previous item. The fix is to reset LPSTR_TEXTCALLBACK + * even though it has not changed, causing Windows to flush + * cached bounds. + */ + if ((style & DWT.VIRTUAL) is 0) { LVITEM lvItem; lvItem.mask = OS.LVIF_TEXT | OS.LVIF_IMAGE; lvItem.pszText = OS.LPSTR_TEXTCALLBACK; @@ -1781,8 +1920,8 @@ item.cellForeground = temp; } if (item.cellFont !is null) { - HFONT [] cellFont = item.cellFont; - HFONT [] temp = new HFONT[]( columnCount ); + Font [] cellFont = item.cellFont; + Font [] temp = new Font [columnCount]; System.arraycopy (cellFont, 0, temp, 0, index); System.arraycopy (cellFont, index + 1, temp, index, columnCount - index); item.cellFont = temp; @@ -1861,7 +2000,7 @@ if (index is count) return; setDeferResize (true); ignoreSelect = ignoreShrink = true; - int code = OS.SendMessage (handle, OS.LVM_DELETEITEM, index, 0); + int /*long*/ code = OS.SendMessage (handle, OS.LVM_DELETEITEM, index, 0); ignoreSelect = ignoreShrink = false; if (code is 0) error (DWT.ERROR_ITEM_NOT_REMOVED); System.arraycopy (items, index + 1, items, index, --count - index); @@ -2186,8 +2325,33 @@ public TableItem getItem (Point point) { checkWidget (); if (point is null) error (DWT.ERROR_NULL_ARGUMENT); + int count = OS.SendMessage (handle, OS.LVM_GETITEMCOUNT, 0, 0); + if (count is 0) return null; LVHITTESTINFO pinfo; - pinfo.pt.x = point.x; pinfo.pt.y = point.y; + pinfo.pt.x = point.x; + pinfo.pt.y = point.y; + if ((style & DWT.FULL_SELECTION) is 0) { + if (hooks (DWT.MeasureItem)) { + OS.SendMessage (handle, OS.LVM_SUBITEMHITTEST, 0, &pinfo); + if (pinfo.iItem is -1) { + RECT rect; + rect.left = OS.LVIR_ICON; + ignoreCustomDraw = true; + int /*long*/ code = OS.SendMessage (handle, OS.LVM_GETITEMRECT, 0, &rect); + ignoreCustomDraw = false; + if (code !is 0) { + pinfo.pt.x = rect.left; + OS.SendMessage (handle, OS.LVM_SUBITEMHITTEST, 0, &pinfo); + } + } + if (pinfo.iItem !is -1 && pinfo.iSubItem is 0) { + if (hitTestSelection (pinfo.iItem, pinfo.pt.x, pinfo.pt.y)) { + return _getItem (pinfo.iItem); + } + } + return null; + } + } OS.SendMessage (handle, OS.LVM_HITTEST, 0, &pinfo); if (pinfo.iItem !is -1) { /* @@ -2235,7 +2399,7 @@ /** * Returns the height of the area which would be used to - * display <em>one</em> of the items in the receiver's. + * display <em>one</em> of the items in the receiver. * * @return the height of one item * @@ -2246,9 +2410,9 @@ */ public int getItemHeight () { checkWidget (); - int empty = OS.SendMessage (handle, OS.LVM_APPROXIMATEVIEWRECT, 0, 0); - int oneItem = OS.SendMessage (handle, OS.LVM_APPROXIMATEVIEWRECT, 1, 0); - return (oneItem >> 16) - (empty >> 16); + int /*long*/ empty = OS.SendMessage (handle, OS.LVM_APPROXIMATEVIEWRECT, 0, 0); + int /*long*/ oneItem = OS.SendMessage (handle, OS.LVM_APPROXIMATEVIEWRECT, 1, 0); + return OS.HIWORD (oneItem) - OS.HIWORD (empty); } /** @@ -2486,6 +2650,28 @@ return false; } +bool hitTestSelection (int index, int x, int y) { + int count = OS.SendMessage (handle, OS.LVM_GETITEMCOUNT, 0, 0); + if (count is 0) return false; + if (!hooks (DWT.MeasureItem)) return false; + bool result = false; + if (0 <= index && index < count) { + TableItem item = _getItem (index); + auto hDC = OS.GetDC (handle); + HFONT oldFont, newFont = cast(HFONT)OS.SendMessage (handle, OS.WM_GETFONT, 0, 0); + if (newFont !is null) oldFont = OS.SelectObject (hDC, newFont); + auto hFont = item.fontHandle (0); + if (hFont !is cast(HFONT)-1) hFont = OS.SelectObject (hDC, hFont); + Event event = sendMeasureItemEvent (item, index, 0, hDC); + if (event.getBounds ().contains (x, y)) result = true; + if (hFont !is cast(HFONT)-1) hFont = OS.SelectObject (hDC, hFont); + if (newFont !is null) OS.SelectObject (hDC, oldFont); + OS.ReleaseDC (handle, hDC); +// if (isDisposed () || item.isDisposed ()) return false; + } + return result; +} + int imageIndex (Image image, int column) { if (image is null) return OS.I_IMAGENONE; if (column is 0) { @@ -2613,6 +2799,15 @@ return -1; } +bool isCustomToolTip () { + return hooks (DWT.MeasureItem); +} + +bool isOptimizedRedraw () { + if ((style & DWT.H_SCROLL) is 0 || (style & DWT.V_SCROLL) is 0) return false; + return !hasChildren () && !hooks (DWT.Paint) && !filters (DWT.Paint); +} + /** * Returns <code>true</code> if the item is selected, * and <code>false</code> otherwise. Indices out of @@ -2744,7 +2939,7 @@ TableItem item = items [index]; if (item !is null && !item.isDisposed ()) item.release (false); ignoreSelect = ignoreShrink = true; - int code = OS.SendMessage (handle, OS.LVM_DELETEITEM, index, 0); + int /*long*/ code = OS.SendMessage (handle, OS.LVM_DELETEITEM, index, 0); ignoreSelect = ignoreShrink = false; if (code is 0) error (DWT.ERROR_ITEM_NOT_REMOVED); System.arraycopy (items, index + 1, items, index, --count - index); @@ -2778,7 +2973,7 @@ if (item !is null && !item.isDisposed ()) item.release (false); setDeferResize (true); ignoreSelect = ignoreShrink = true; - int code = OS.SendMessage (handle, OS.LVM_DELETEITEM, index, 0); + int /*long*/ code = OS.SendMessage (handle, OS.LVM_DELETEITEM, index, 0); ignoreSelect = ignoreShrink = false; if (code is 0) error (DWT.ERROR_ITEM_NOT_REMOVED); System.arraycopy (items, index + 1, items, index, --count - index); @@ -2819,7 +3014,7 @@ TableItem item = items [index]; if (item !is null && !item.isDisposed ()) item.release (false); ignoreSelect = ignoreShrink = true; - int code = OS.SendMessage (handle, OS.LVM_DELETEITEM, start, 0); + int /*long*/ code = OS.SendMessage (handle, OS.LVM_DELETEITEM, start, 0); ignoreSelect = ignoreShrink = false; if (code is 0) break; index++; @@ -2873,7 +3068,7 @@ int index = itemCount - 1; while (index >= 0) { ignoreSelect = ignoreShrink = true; - int code = OS.SendMessage (handle, OS.LVM_DELETEITEM, index, 0); + int /*long*/ code = OS.SendMessage (handle, OS.LVM_DELETEITEM, index, 0); ignoreSelect = ignoreShrink = false; if (code is 0) break; --index; @@ -2892,7 +3087,7 @@ if (index !is -1) error (DWT.ERROR_ITEM_NOT_REMOVED); } else { ignoreSelect = ignoreShrink = true; - int code = OS.SendMessage (handle, OS.LVM_DELETEALLITEMS, 0, 0); + int /*long*/ code = OS.SendMessage (handle, OS.LVM_DELETEALLITEMS, 0, 0); ignoreSelect = ignoreShrink = false; if (code is 0) error (DWT.ERROR_ITEM_NOT_REMOVED); } @@ -3067,10 +3262,8 @@ ignoreSelect = false; } -void sendEraseItemEvent (TableItem item, NMLVCUSTOMDRAW* nmcd, int lParam) { +void sendEraseItemEvent (TableItem item, NMLVCUSTOMDRAW* nmcd, int lParam, Event measureEvent) { auto hDC = nmcd.nmcd.hdc; - auto hFont = item.cellFont !is null ? item.cellFont [nmcd.iSubItem] : cast(HFONT)-1; - if (hFont is cast(HFONT)-1) hFont = item.font; int clrText = item.cellForeground !is null ? item.cellForeground [nmcd.iSubItem] : -1; if (clrText is -1) clrText = item.foreground; int clrTextBk = -1; @@ -3105,7 +3298,7 @@ } if (OS.IsWindowEnabled (handle)) { if (selected && (nmcd.iSubItem is 0 || (style & DWT.FULL_SELECTION) !is 0)) { - if (OS.GetFocus () is handle) { + if (OS.GetFocus () is handle || display.getHighContrast ()) { drawSelected = true; data.foreground = OS.GetSysColor (OS.COLOR_HIGHLIGHTTEXT); data.background = clrSelectionBk = OS.GetSysColor (OS.COLOR_HIGHLIGHT); @@ -3120,16 +3313,17 @@ } else { drawBackground = clrTextBk !is -1; /* - * Bug in Windows. When LVM_SETTEXTBKCOLOR or LVM_SETBKCOLOR - * is used to set the background color of the the text or the - * control, the color is not set in the HDC that is provided - * in Custom Draw. The fix is to explicitly set the background - * color. + * Bug in Windows. When LVM_SETTEXTBKCOLOR, LVM_SETBKCOLOR + * or LVM_SETTEXTCOLOR is used to set the background color of + * the the text or the control, the color is not set in the HDC + * that is provided in Custom Draw. The fix is to explicitly + * set the color. */ - if (clrTextBk is -1) { + if (clrText is -1 || clrTextBk is -1) { Control control = findBackgroundControl (); if (control is null) control = this; - clrTextBk = control.getBackgroundPixel (); + if (clrText is -1) clrText = control.getForegroundPixel (); + if (clrTextBk is -1) clrTextBk = control.getBackgroundPixel (); } data.foreground = clrText !is -1 ? clrText : OS.GetTextColor (hDC); data.background = clrTextBk !is -1 ? clrTextBk : OS.GetBkColor (hDC); @@ -3139,7 +3333,7 @@ data.background = OS.GetSysColor (OS.COLOR_3DFACE); if (selected) clrSelectionBk = data.background; } - data.hFont = hFont; + data.font = item.getFont (nmcd.iSubItem); data.uiState = OS.SendMessage (handle, OS.WM_QUERYUISTATE, 0, 0); auto nSavedDC = OS.SaveDC (hDC); GC gc = GC.win32_new (hDC, data); @@ -3158,6 +3352,7 @@ } } } + bool focused = (event.detail & DWT.FOCUSED) !is 0; if (drawHot) event.detail |= DWT.HOT; if (drawSelected) event.detail |= DWT.SELECTED; if (drawBackground) event.detail |= DWT.BACKGROUND; @@ -3196,10 +3391,7 @@ OS.MoveMemory (lParam, nmcd, NMLVCUSTOMDRAW.sizeof); } } - if (ignoreDrawFocus) { - nmcd.nmcd.uItemState &= ~OS.CDIS_FOCUS; - OS.MoveMemory (lParam, nmcd, NMLVCUSTOMDRAW.sizeof); - } + auto hwndHeader = cast(HWND) OS.SendMessage (handle, OS.LVM_GETHEADER, 0, 0); bool firstColumn = nmcd.iSubItem is OS.SendMessage (hwndHeader, OS.HDM_ORDERTOINDEX, 0, 0); if (ignoreDrawForeground && ignoreDrawHot) { @@ -3208,37 +3400,55 @@ fillBackground (hDC, clrTextBk, &backgroundRect); } } - if (!ignoreDrawHot || (!ignoreDrawSelection && clrSelectionBk !is -1)) { + focusRect = null; + if (!ignoreDrawHot || !ignoreDrawSelection || !ignoreDrawFocus) { + bool fullText = (style & DWT.FULL_SELECTION) !is 0 || !firstColumn; + RECT textRect = item.getBounds (nmcd.nmcd.dwItemSpec, nmcd.iSubItem, true, false, fullText, false, hDC); + if ((style & DWT.FULL_SELECTION) is 0) { + if (measureEvent !is null) { + textRect.right = Math.min (cellRect.right, measureEvent.x + measureEvent.width); + } + if (!ignoreDrawFocus) { + nmcd.nmcd.uItemState &= ~OS.CDIS_FOCUS; + OS.MoveMemory (cast(void*)lParam, &nmcd, NMLVCUSTOMDRAW.sizeof); + focusRect = new RECT; + *focusRect = textRect; + } + } if (explorerTheme) { - bool hot = drawHot; - RECT pClipRect; - OS.SetRect (&pClipRect, nmcd.nmcd.rc.left, nmcd.nmcd.rc.top, nmcd.nmcd.rc.right, nmcd.nmcd.rc.bottom); - RECT rect; - OS.SetRect (&rect, nmcd.nmcd.rc.left, nmcd.nmcd.rc.top, nmcd.nmcd.rc.right, nmcd.nmcd.rc.bottom); - if ((style & DWT.FULL_SELECTION) !is 0) { - int count = OS.SendMessage (hwndHeader, OS.HDM_GETITEMCOUNT, 0, 0); - int index = OS.SendMessage (hwndHeader, OS.HDM_ORDERTOINDEX, count - 1, 0); - RECT headerRect; - OS.SendMessage (hwndHeader, OS.HDM_GETITEMRECT, index, &headerRect); - OS.MapWindowPoints (hwndHeader, handle, cast(POINT*) &headerRect, 2); - rect.left = 0; - rect.right = headerRect.right; - pClipRect.left = cellRect.left; - pClipRect.right += EXPLORER_EXTRA; - } else { - rect.right += EXPLORER_EXTRA; - pClipRect.right += EXPLORER_EXTRA; + if (!ignoreDrawHot || (!ignoreDrawSelection && clrSelectionBk !is -1)) { + bool hot = drawHot; + RECT pClipRect; + OS.SetRect (&pClipRect, nmcd.nmcd.rc.left, nmcd.nmcd.rc.top, nmcd.nmcd.rc.right, nmcd.nmcd.rc.bottom); + RECT rect; + OS.SetRect (&rect, nmcd.nmcd.rc.left, nmcd.nmcd.rc.top, nmcd.nmcd.rc.right, nmcd.nmcd.rc.bottom); + if ((style & DWT.FULL_SELECTION) !is 0) { + int count = OS.SendMessage (hwndHeader, OS.HDM_GETITEMCOUNT, 0, 0); + int index = OS.SendMessage (hwndHeader, OS.HDM_ORDERTOINDEX, count - 1, 0); + RECT headerRect; + OS.SendMessage (hwndHeader, OS.HDM_GETITEMRECT, index, &headerRect); + OS.MapWindowPoints (hwndHeader, handle, cast(POINT*) &headerRect, 2); + rect.left = 0; + rect.right = headerRect.right; + pClipRect.left = cellRect.left; + pClipRect.right += EXPLORER_EXTRA; + } else { + rect.right += EXPLORER_EXTRA; + pClipRect.right += EXPLORER_EXTRA; + } + auto hTheme = OS.OpenThemeData (handle, Display.LISTVIEW.ptr); + int iStateId = selected ? OS.LISS_SELECTED : OS.LISS_HOT; + if (OS.GetFocus () !is handle && selected && !hot) iStateId = OS.LISS_SELECTEDNOTFOCUS; + OS.DrawThemeBackground (hTheme, hDC, OS.LVP_LISTITEM, iStateId, &rect, &pClipRect); + OS.CloseThemeData (hTheme); } - auto hTheme = OS.OpenThemeData (handle, Display.LISTVIEW.ptr); - int iStateId = selected ? OS.LISS_SELECTED : OS.LISS_HOT; - if (OS.GetFocus () !is handle && selected && !hot) iStateId = OS.LISS_SELECTEDNOTFOCUS; - OS.DrawThemeBackground (hTheme, hDC, OS.LVP_LISTITEM, iStateId, &rect, &pClipRect); - OS.CloseThemeData (hTheme); } else { - bool fullText = ((style & DWT.FULL_SELECTION) !is 0 || !firstColumn); - RECT textRect = item.getBounds (nmcd.nmcd.dwItemSpec, nmcd.iSubItem, true, false, fullText, false, hDC); - fillBackground (hDC, clrSelectionBk, &textRect); - } + if (!ignoreDrawSelection && clrSelectionBk !is -1) fillBackground (hDC, clrSelectionBk, &textRect); + } + } + if (focused && ignoreDrawFocus) { + nmcd.nmcd.uItemState &= ~OS.CDIS_FOCUS; + OS.MoveMemory (lParam, nmcd, NMLVCUSTOMDRAW.sizeof); } if (ignoreDrawForeground) { RECT clipRect = item.getBounds (nmcd.nmcd.dwItemSpec, nmcd.iSubItem, true, true, true, false, hDC); @@ -3248,13 +3458,40 @@ } } -Event sendMeasureItemEvent (TableItem item, int row, int column, HDC hDC) { - auto hFont = item.cellFont !is null ? item.cellFont [column] : cast(HFONT)-1; - if (hFont is cast(HFONT)-1) hFont = item.font; +Event sendEraseItemEvent (TableItem item, NMTTCUSTOMDRAW* nmcd, int column, RECT* cellRect) { + int nSavedDC = OS.SaveDC (nmcd.nmcd.hdc); + RECT* insetRect = toolTipInset (cellRect); + OS.SetWindowOrgEx (nmcd.nmcd.hdc, insetRect.left, insetRect.top, null); GCData data = new GCData (); data.device = display; - data.hFont = hFont; - auto nSavedDC = OS.SaveDC (hDC); + data.foreground = OS.GetTextColor (nmcd.nmcd.hdc); + data.background = OS.GetBkColor (nmcd.nmcd.hdc); + data.font = item.getFont (column); + data.uiState = OS.SendMessage (handle, OS.WM_QUERYUISTATE, 0, 0); + GC gc = GC.win32_new (nmcd.nmcd.hdc, data); + Event event = new Event (); + event.item = item; + event.index = column; + event.gc = gc; + event.detail |= DWT.FOREGROUND; + event.x = cellRect.left; + event.y = cellRect.top; + event.width = cellRect.right - cellRect.left; + event.height = cellRect.bottom - cellRect.top; + //gc.setClipping (event.x, event.y, event.width, event.height); + sendEvent (DWT.EraseItem, event); + event.gc = null; + //int newTextClr = data.foreground; + gc.dispose (); + OS.RestoreDC (nmcd.nmcd.hdc, nSavedDC); + return event; +} + +Event sendMeasureItemEvent (TableItem item, int row, int column, HDC hDC) { + GCData data = new GCData (); + data.device = display; + data.font = item.getFont (column); + int nSavedDC = OS.SaveDC (hDC); GC gc = GC.win32_new (hDC, data); RECT itemRect = item.getBounds (row, column, true, true, false, false, hDC); Event event = new Event (); @@ -3281,7 +3518,16 @@ return event; } -LRESULT sendMouseDownEvent (int type, int button, int msg, int wParam, int lParam) { +LRESULT sendMouseDownEvent (int type, int button, int msg, int /*long*/ wParam, int /*long*/ lParam) { + Display display = this.display; + display.captureChanged = false; + if (!sendMouseEvent (type, button, handle, msg, wParam, lParam)) { + if (!display.captureChanged && !isDisposed ()) { + if (OS.GetCapture () !is handle) OS.SetCapture (handle); + } + return LRESULT.ZERO; + } + /* * Feature in Windows. Inside WM_LBUTTONDOWN and WM_RBUTTONDOWN, * the widget starts a modal loop to determine if the user wants @@ -3295,16 +3541,30 @@ * the widget does not eat the mouse up. */ LVHITTESTINFO pinfo; - pinfo.pt.x = cast(short) (lParam & 0xFFFF); - pinfo.pt.y = cast(short) (lParam >> 16); + pinfo.pt.x = OS.GET_X_LPARAM (lParam); + pinfo.pt.y = OS.GET_Y_LPARAM (lParam); OS.SendMessage (handle, OS.LVM_HITTEST, 0, &pinfo); - Display display = this.display; - display.captureChanged = false; - if (!sendMouseEvent (type, button, handle, msg, wParam, lParam)) { - if (!display.captureChanged && !isDisposed ()) { - if (OS.GetCapture () !is handle) OS.SetCapture (handle); - } - return LRESULT.ZERO; + if ((style & DWT.FULL_SELECTION) is 0) { + if (hooks (DWT.MeasureItem)) { + OS.SendMessage (handle, OS.LVM_SUBITEMHITTEST, 0, &pinfo); + if (pinfo.iItem is -1) { + int count = OS.SendMessage (handle, OS.LVM_GETITEMCOUNT, 0, 0); + if (count !is 0) { + RECT rect; + rect.left = OS.LVIR_ICON; + ignoreCustomDraw = true; + int /*long*/ code = OS.SendMessage (handle, OS.LVM_GETITEMRECT, 0, &rect); + ignoreCustomDraw = false; + if (code !is 0) { + pinfo.pt.x = rect.left; + OS.SendMessage (handle, OS.LVM_SUBITEMHITTEST, 0, &pinfo); + pinfo.flags &= ~(OS.LVHT_ONITEMICON | OS.LVHT_ONITEMLABEL); + } + } + } else { + if (pinfo.iSubItem !is 0) pinfo.iItem = -1; + } + } } /* @@ -3354,6 +3614,21 @@ forceSelect = true; } } + + /* Determine whether the user has selected an item based on DWT.MeasureItem */ + fullRowSelect = false; + if (pinfo.iItem !is -1) { + if ((style & DWT.FULL_SELECTION) is 0) { + if (hooks (DWT.MeasureItem)) { + fullRowSelect = hitTestSelection (pinfo.iItem, pinfo.pt.x, pinfo.pt.y); + if (fullRowSelect) { + int flags = OS.LVHT_ONITEMICON | OS.LVHT_ONITEMLABEL; + if ((pinfo.flags & flags) !is 0) fullRowSelect = false; + } + } + } + } + /* * Feature in Windows. Inside WM_LBUTTONDOWN and WM_RBUTTONDOWN, * the widget starts a modal loop to determine if the user wants @@ -3366,11 +3641,31 @@ if (!dragDetect) { int flags = OS.LVHT_ONITEMICON | OS.LVHT_ONITEMLABEL; dragDetect = pinfo.iItem is -1 || (pinfo.flags & flags) is 0; - } + if (fullRowSelect) dragDetect = true; + } + + /* + * Temporarily set LVS_EX_FULLROWSELECT to allow drag and drop + * and the mouse to manipulate items based on the results of + * the DWT.MeasureItem event. + */ + if (fullRowSelect) { + OS.UpdateWindow (handle); + OS.DefWindowProc (handle, OS.WM_SETREDRAW, 0, 0); + OS.SendMessage (handle, OS.LVM_SETEXTENDEDLISTVIEWSTYLE, OS.LVS_EX_FULLROWSELECT, OS.LVS_EX_FULLROWSELECT); + } + dragStarted = false; + display.dragCancelled = false; if (!dragDetect) display.runDragDrop = false; - int code = callWindowProc (handle, msg, wParam, lParam, forceSelect); + int /*long*/ code = callWindowProc (handle, msg, wParam, lParam, forceSelect); if (!dragDetect) display.runDragDrop = true; - if (dragStarted || !dragDetect) { + if (fullRowSelect) { + fullRowSelect = false; + OS.DefWindowProc (handle, OS.WM_SETREDRAW, 1, 0); + OS.SendMessage (handle, OS.LVM_SETEXTENDEDLISTVIEWSTYLE, OS.LVS_EX_FULLROWSELECT, 0); + } + + if (dragStarted || display.dragCancelled) { if (!display.captureChanged && !isDisposed ()) { if (OS.GetCapture () !is handle) OS.SetCapture (handle); } @@ -3384,7 +3679,6 @@ sendMouseEvent (DWT.MouseUp, button, handle, msg, wParam, lParam); } } - dragStarted = false; return new LRESULT (code); } @@ -3392,9 +3686,7 @@ auto hDC = nmcd.nmcd.hdc; GCData data = new GCData (); data.device = display; - auto hFont = item.cellFont !is null ? item.cellFont [nmcd.iSubItem] : cast(HFONT)-1; - if (hFont is cast(HFONT)-1) hFont = item.font; - data.hFont = hFont; + data.font = item.getFont (nmcd.iSubItem); /* * Bug in Windows. For some reason, CDIS_SELECTED always set, * even for items that are not selected. The fix is to get @@ -3412,7 +3704,7 @@ } if (OS.IsWindowEnabled (handle)) { if (selected && (nmcd.iSubItem is 0 || (style & DWT.FULL_SELECTION) !is 0)) { - if (OS.GetFocus () is handle) { + if (OS.GetFocus () is handle || display.getHighContrast ()) { drawSelected = true; if (selectionForeground !is -1) { data.foreground = selectionForeground; @@ -3437,16 +3729,17 @@ if (clrTextBk is -1) clrTextBk = item.background; drawBackground = clrTextBk !is -1; /* - * Bug in Windows. When LVM_SETTEXTBKCOLOR or LVM_SETBKCOLOR - * is used to set the background color of the the text or the - * control, the color is not set in the HDC that is provided - * in Custom Draw. The fix is to explicitly set the background - * color. + * Bug in Windows. When LVM_SETTEXTBKCOLOR, LVM_SETBKCOLOR + * or LVM_SETTEXTCOLOR is used to set the background color of + * the the text or the control, the color is not set in the HDC + * that is provided in Custom Draw. The fix is to explicitly + * set the color. */ - if (clrTextBk is -1) { + if (clrText is -1 || clrTextBk is -1) { Control control = findBackgroundControl (); if (control is null) control = this; - clrTextBk = control.getBackgroundPixel (); + if (clrText is -1) clrText = control.getForegroundPixel (); + if (clrTextBk is -1) clrTextBk = control.getBackgroundPixel (); } data.foreground = clrText !is -1 ? clrText : OS.GetTextColor (hDC); data.background = clrTextBk !is -1 ? clrTextBk : OS.GetBkColor (hDC); @@ -3485,21 +3778,56 @@ int cellHeight = cellRect.bottom - cellRect.top; gc.setClipping (cellRect.left, cellRect.top, cellWidth, cellHeight); sendEvent (DWT.PaintItem, event); + if (data.focusDrawn) focusRect = null; event.gc = null; gc.dispose (); OS.RestoreDC (hDC, nSavedDC); } -override void setBackgroundImage (HBITMAP hBitmap) { +Event sendPaintItemEvent (TableItem item, NMTTCUSTOMDRAW* nmcd, int column, RECT* itemRect) { + int nSavedDC = OS.SaveDC (nmcd.nmcd.hdc); + RECT* insetRect = toolTipInset (itemRect); + OS.SetWindowOrgEx (nmcd.nmcd.hdc, insetRect.left, insetRect.top, null); + GCData data = new GCData (); + data.device = display; + data.font = item.getFont (column); + data.foreground = OS.GetTextColor (nmcd.nmcd.hdc); + data.background = OS.GetBkColor (nmcd.nmcd.hdc); + data.uiState = OS.SendMessage (handle, OS.WM_QUERYUISTATE, 0, 0); + GC gc = GC.win32_new (nmcd.nmcd.hdc, data); + Event event = new Event (); + event.item = item; + event.index = column; + event.gc = gc; + event.detail |= DWT.FOREGROUND; + event.x = itemRect.left; + event.y = itemRect.top; + event.width = itemRect.right - itemRect.left; + event.height = itemRect.bottom - itemRect.top; + //gc.setClipping (cellRect.left, cellRect.top, cellWidth, cellHeight); + sendEvent (DWT.PaintItem, event); + event.gc = null; + gc.dispose (); + OS.RestoreDC (nmcd.nmcd.hdc, nSavedDC); + return event; +} + +void setBackgroundImage (HBITMAP hBitmap) { super.setBackgroundImage (hBitmap); - if (!customDraw) setBackgroundTransparent (hBitmap !is null); + if (hBitmap !is null) { + setBackgroundTransparent (true); + } else { + if (!hooks (DWT.MeasureItem) && !hooks (DWT.EraseItem) && !hooks (DWT.PaintItem)) { + setBackgroundTransparent (false); + } + } } override void setBackgroundPixel (int newPixel) { - if (!customDraw) { + int oldPixel = OS.SendMessage (handle, OS.LVM_GETBKCOLOR, 0, 0); + if (oldPixel !is OS.CLR_NONE) { if (findImageControl () !is null) return; if (newPixel is -1) newPixel = defaultBackground (); - int oldPixel = OS.SendMessage (handle, OS.LVM_GETBKCOLOR, 0, 0); if (oldPixel !is newPixel) { OS.SendMessage (handle, OS.LVM_SETBKCOLOR, 0, newPixel); OS.SendMessage (handle, OS.LVM_SETTEXTBKCOLOR, 0, newPixel); @@ -3565,7 +3893,11 @@ Control control = findBackgroundControl (); if (control is null) control = this; if (control.backgroundImage is null) { - setBackgroundPixel (control.getBackgroundPixel ()); + int newPixel = control.getBackgroundPixel (); + OS.SendMessage (handle, OS.LVM_SETBKCOLOR, 0, newPixel); + OS.SendMessage (handle, OS.LVM_SETTEXTBKCOLOR, 0, newPixel); + if ((style & DWT.CHECK) !is 0) fixCheckboxImageListColor (true); + OS.InvalidateRect (handle, null, true); } /* Set LVS_EX_FULLROWSELECT */ @@ -3701,9 +4033,16 @@ if (defer) { if (resizeCount++ is 0) { wasResized = false; + /* + * Feature in Windows. When LVM_SETBKCOLOR is used with CLR_NONE + * to make the background of the table transparent, drawing becomes + * slow. The fix is to temporarily clear CLR_NONE when redraw is + * turned off. + */ if (hooks (DWT.MeasureItem) || hooks (DWT.EraseItem) || hooks (DWT.PaintItem)) { if (drawCount++ is 0 && OS.IsWindowVisible (handle)) { OS.DefWindowProc (handle, OS.WM_SETREDRAW, 0, 0); + OS.SendMessage (handle, OS.LVM_SETBKCOLOR, 0, 0xFFFFFF); } } } @@ -3711,6 +4050,7 @@ if (--resizeCount is 0) { if (hooks (DWT.MeasureItem) || hooks (DWT.EraseItem) || hooks (DWT.PaintItem)) { if (--drawCount is 0 /*&& OS.IsWindowVisible (handle)*/) { + OS.SendMessage (handle, OS.LVM_SETBKCOLOR, 0, OS.CLR_NONE); OS.DefWindowProc (handle, OS.WM_SETREDRAW, 1, 0); static if (OS.IsWinCE) { auto hwndHeader = cast(HWND) OS.SendMessage (handle, OS.LVM_GETHEADER, 0, 0); @@ -4004,7 +4344,7 @@ if (item !is null && !item.isDisposed ()) item.release (false); if (!isVirtual) { ignoreSelect = ignoreShrink = true; - int code = OS.SendMessage (handle, OS.LVM_DELETEITEM, count, 0); + int /*long*/ code = OS.SendMessage (handle, OS.LVM_DELETEITEM, count, 0); ignoreSelect = ignoreShrink = false; if (code is 0) break; } @@ -4241,25 +4581,23 @@ int itemCount = OS.SendMessage (handle, OS.LVM_GETITEMCOUNT, 0, 0); while (index < itemCount) { String string = null; - HFONT font = cast(HFONT)-1; + HFONT hFont = cast(HFONT)-1; if (item !is null) { string = item.text; imageIndent = Math.max (imageIndent, item.imageIndent); - if (item.cellFont !is null) font = item.cellFont [0]; - if (font is cast(HFONT)-1) font = item.font; + hFont = item.fontHandle (0); } else { if (items [index] !is null) { TableItem tableItem = items [index]; string = tableItem.text; imageIndent = Math.max (imageIndent, tableItem.imageIndent); - if (tableItem.cellFont !is null) font = tableItem.cellFont [0]; - if (font is cast(HFONT)-1) font = tableItem.font; + hFont = tableItem.fontHandle (0); } } if (string !is null && string.length !is 0) { - if (font !is cast(HFONT)-1) { + if (hFont !is cast(HFONT)-1) { auto hDC = OS.GetDC (handle); - auto oldFont = OS.SelectObject (hDC, font); + auto oldFont = OS.SelectObject (hDC, hFont); int flags = OS.DT_CALCRECT | OS.DT_SINGLELINE | OS.DT_NOPREFIX; TCHAR[] buffer = StrToTCHARs (getCodePage (), string, false); RECT rect; @@ -4865,8 +5203,31 @@ super.subclass (); if (HeaderProc !is null) { auto hwndHeader = cast(HWND) OS.SendMessage (handle, OS.LVM_GETHEADER, 0, 0); - OS.SetWindowLong (hwndHeader, OS.GWL_WNDPROC, display.windowProc); - } + OS.SetWindowLongPtr (hwndHeader, OS.GWLP_WNDPROC, display.windowProc); + } +} + +RECT* toolTipInset (RECT* rect) { + if (!OS.IsWinCE && OS.WIN32_VERSION >= OS.VERSION (6, 0)) { + RECT* insetRect = new RECT; + OS.SetRect (insetRect, rect.left - 1, rect.top - 1, rect.right + 1, rect.bottom + 1); + return insetRect; + } + return rect; +} + +RECT* toolTipRect (RECT* rect) { + RECT* toolRect = new RECT; + if (!OS.IsWinCE && OS.WIN32_VERSION >= OS.VERSION (6, 0)) { + OS.SetRect (toolRect, rect.left - 1, rect.top - 1, rect.right + 1, rect.bottom + 1); + } else { + HWND hwndToolTip = cast(HWND)OS.SendMessage (handle, OS.LVM_GETTOOLTIPS, 0, 0); + OS.SetRect (toolRect, rect.left, rect.top, rect.right, rect.bottom); + int dwStyle = OS.GetWindowLong (hwndToolTip, OS.GWL_STYLE); + int dwExStyle = OS.GetWindowLong (hwndToolTip, OS.GWL_EXSTYLE); + OS.AdjustWindowRectEx (toolRect, dwStyle, false, dwExStyle); + } + return toolRect; } override String toolTipText (NMTTDISPINFO* hdr) { @@ -4885,7 +5246,7 @@ super.unsubclass (); if (HeaderProc !is null) { auto hwndHeader = cast(HWND) OS.SendMessage (handle, OS.LVM_GETHEADER, 0, 0); - OS.SetWindowLong (hwndHeader, OS.GWL_WNDPROC, cast(int) HeaderProc); + OS.SetWindowLongPtr (hwndHeader, OS.GWLP_WNDPROC, cast(LONG_PTR)HeaderProc); } } @@ -4904,15 +5265,15 @@ */ WNDPROC oldHeaderProc, oldTableProc; auto hwndHeader = cast(HWND) OS.SendMessage (handle, OS.LVM_GETHEADER, 0, 0); - bool fixSubclass = !hasChildren () && !hooks (DWT.Paint) && !filters (DWT.Paint); + bool fixSubclass = isOptimizedRedraw (); if (fixSubclass) { - oldTableProc = cast(WNDPROC) OS.SetWindowLong (handle, OS.GWL_WNDPROC, cast(int) TableProc); - oldHeaderProc = cast(WNDPROC) OS.SetWindowLong (hwndHeader, OS.GWL_WNDPROC, cast(int) HeaderProc); + oldTableProc = cast(WNDPROC)OS.SetWindowLongPtr (handle, OS.GWLP_WNDPROC, cast(LONG_PTR)TableProc); + oldHeaderProc = cast(WNDPROC)OS.SetWindowLongPtr (hwndHeader, OS.GWLP_WNDPROC, cast(LONG_PTR)HeaderProc); } super.update (all); if (fixSubclass) { - OS.SetWindowLong (handle, OS.GWL_WNDPROC, cast(int) oldTableProc); - OS.SetWindowLong (hwndHeader, OS.GWL_WNDPROC, cast(int) oldHeaderProc); + OS.SetWindowLongPtr (handle, OS.GWLP_WNDPROC, cast(LONG_PTR)oldTableProc); + OS.SetWindowLongPtr (hwndHeader, OS.GWLP_WNDPROC, cast(LONG_PTR)oldHeaderProc); } } @@ -5044,13 +5405,12 @@ } case OS.WM_SETCURSOR: { if (wParam is cast(int)hwnd) { - int hitTest = cast(short) (lParam & 0xFFFF); + int hitTest = cast(short) OS.LOWORD (lParam); if (hitTest is OS.HTCLIENT) { HDHITTESTINFO pinfo; int pos = OS.GetMessagePos (); POINT pt; - pt.x = cast(short) (pos & 0xFFFF); - pt.y = cast(short) (pos >> 16); + OS.POINTSTOPOINT (pt, pos); OS.ScreenToClient (hwnd, &pt); pinfo.pt.x = pt.x; pinfo.pt.y = pt.y; @@ -5070,6 +5430,19 @@ } return callWindowProc (hwnd, msg, wParam, lParam); } + if (msg is Display.DI_GETDRAGIMAGE) { + /* + * Bug in Windows. For some reason, DI_GETDRAGIMAGE + * returns an image that does not contain strings. + * The fix is to disable the table window proc. + * + * NOTE: This only happens on Vista. + */ + if (!OS.IsWinCE && OS.WIN32_VERSION >= OS.VERSION (6, 0)) return 0; + //TEMPORARY CODE + if (hooks (DWT.EraseItem) || hooks (DWT.PaintItem)) return 0; +// if (getSelectionCount () !is 1) return 0; + } return super.windowProc (hwnd, msg, wParam, lParam); } @@ -5094,7 +5467,7 @@ * This allows the application to cancel an operation that is normally * performed in WM_KEYDOWN from WM_CHAR. */ - int code = callWindowProc (handle, OS.WM_KEYDOWN, wParam, lParam); + int /*long*/ code = callWindowProc (handle, OS.WM_KEYDOWN, wParam, lParam); return new LRESULT (code); case DWT.CR: /* @@ -5203,18 +5576,18 @@ * NOTE: The header tooltip can subclass the header proc so the * current proc must be restored or header tooltips stop working. */ - int oldHeaderProc = 0, oldTableProc = 0; + int /*long*/ oldHeaderProc = 0, oldTableProc = 0; auto hwndHeader = cast(HWND) OS.SendMessage (handle, OS.LVM_GETHEADER, 0, 0); - bool fixSubclass = !hasChildren () && !hooks (DWT.Paint) && !filters (DWT.Paint); + bool fixSubclass = isOptimizedRedraw (); if (fixSubclass) { - oldTableProc = OS.SetWindowLong (handle, OS.GWL_WNDPROC, cast(int) TableProc); - oldHeaderProc = OS.SetWindowLong (hwndHeader, OS.GWL_WNDPROC, cast(int) HeaderProc); + oldTableProc = OS.SetWindowLongPtr (handle, OS.GWLP_WNDPROC, cast(LONG_PTR)TableProc); + oldHeaderProc = OS.SetWindowLongPtr (hwndHeader, OS.GWLP_WNDPROC, cast(LONG_PTR)HeaderProc); } - int code = callWindowProc (handle, OS.WM_KEYDOWN, wParam, lParam); + int /*long*/ code = callWindowProc (handle, OS.WM_KEYDOWN, wParam, lParam); result = code is 0 ? LRESULT.ZERO : new LRESULT (code); if (fixSubclass) { - OS.SetWindowLong (handle, OS.GWL_WNDPROC, oldTableProc); - OS.SetWindowLong (hwndHeader, OS.GWL_WNDPROC, oldHeaderProc); + OS.SetWindowLongPtr (handle, OS.GWLP_WNDPROC, oldTableProc); + OS.SetWindowLongPtr (hwndHeader, OS.GWLP_WNDPROC, oldHeaderProc); } //FALL THROUGH case OS.VK_UP: @@ -5250,8 +5623,8 @@ * case and avoid calling the window proc. */ LVHITTESTINFO pinfo; - pinfo.pt.x = cast(short) (lParam & 0xFFFF); - pinfo.pt.y = cast(short) (lParam >> 16); + pinfo.pt.x = OS.GET_X_LPARAM (lParam); + pinfo.pt.y = OS.GET_Y_LPARAM (lParam); int index = OS.SendMessage (handle, OS.LVM_HITTEST, 0, &pinfo); Display display = this.display; display.captureChanged = false; @@ -5302,8 +5675,8 @@ /* Look for check/uncheck */ if ((style & DWT.CHECK) !is 0) { LVHITTESTINFO pinfo; - pinfo.pt.x = cast(short) (lParam & 0xFFFF); - pinfo.pt.y = cast(short) (lParam >> 16); + pinfo.pt.x = OS.GET_X_LPARAM (lParam); + pinfo.pt.y = OS.GET_Y_LPARAM (lParam); /* * Note that when the table has LVS_EX_FULLROWSELECT and the * user clicks anywhere on a row except on the check box, all @@ -5422,8 +5795,8 @@ * case and avoid calling the window proc. */ LVHITTESTINFO pinfo; - pinfo.pt.x = cast(short) (lParam & 0xFFFF); - pinfo.pt.y = cast(short) (lParam >> 16); + pinfo.pt.x = OS.GET_X_LPARAM (lParam); + pinfo.pt.y = OS.GET_Y_LPARAM (lParam); OS.SendMessage (handle, OS.LVM_HITTEST, 0, &pinfo); Display display = this.display; display.captureChanged = false; @@ -5507,7 +5880,32 @@ return result; } -override LRESULT WM_SIZE (int wParam, int lParam) { +override LRESULT WM_SETREDRAW (int wParam, int lParam) { + LRESULT result = super.WM_SETREDRAW (wParam, lParam); + if (result !is null) return result; + /* + * Feature in Windows. When LVM_SETBKCOLOR is used with CLR_NONE + * to make the background of the table transparent, drawing becomes + * slow. The fix is to temporarily clear CLR_NONE when redraw is + * turned off. + */ + if (wParam is 1) { + if (OS.SendMessage (handle, OS.LVM_GETBKCOLOR, 0, 0) !is OS.CLR_NONE) { + if (hooks (DWT.MeasureItem) || hooks (DWT.EraseItem) || hooks (DWT.PaintItem)) { + OS.SendMessage (handle, OS.LVM_SETBKCOLOR, 0, OS.CLR_NONE); + } + } + } + int /*long*/ code = callWindowProc (handle, OS.WM_SETREDRAW, wParam, lParam); + if (wParam is 0) { + if (OS.SendMessage (handle, OS.LVM_GETBKCOLOR, 0, 0) is OS.CLR_NONE) { + OS.SendMessage (handle, OS.LVM_SETBKCOLOR, 0, 0xFFFFFF); + } + } + return code is 0 ? LRESULT.ZERO : new LRESULT (code); +} + +override LRESULT WM_SIZE (int /*long*/ wParam, int /*long*/ lParam) { if (ignoreResize) return null; if (hooks (DWT.EraseItem) || hooks (DWT.PaintItem)) { OS.InvalidateRect (handle, null, true); @@ -5525,8 +5923,11 @@ if (findBackgroundControl () is null) { setBackgroundPixel (defaultBackground ()); } else { - if ((style & DWT.CHECK) !is 0) { - fixCheckboxImageListColor (true); + int oldPixel = OS.SendMessage (handle, OS.LVM_GETBKCOLOR, 0, 0); + if (oldPixel !is OS.CLR_NONE) { + if (findImageControl () is null) { + if ((style & DWT.CHECK) !is 0) fixCheckboxImageListColor (true); + } } } return result; @@ -5551,27 +5952,78 @@ } /* - * When there are many columns in a table, scrolling performance - * can be improved by temporarily unsubclassing the window proc - * so that internal messages are dispatched directly to the table. - * If the application expects to see a paint event or has a child - * whose font, foreground or background color might be needed, - * the window proc cannot be unsubclassed + * Feature in Windows. When there are many columns in a table, + * scrolling performance can be improved by unsubclassing the + * window proc so that internal messages are dispatched directly + * to the table. If the application expects to see a paint event + * or has a child whose font, foreground or background color might + * be needed, the window proc cannot be unsubclassed * * NOTE: The header tooltip can subclass the header proc so the * current proc must be restored or header tooltips stop working. */ - int oldHeaderProc = 0, oldTableProc = 0; + WNDPROC oldHeaderProc, oldTableProc; auto hwndHeader = cast(HWND) OS.SendMessage (handle, OS.LVM_GETHEADER, 0, 0); - bool fixSubclass = !hasChildren () && !hooks (DWT.Paint) && !filters (DWT.Paint); + bool fixSubclass = isOptimizedRedraw (); if (fixSubclass) { - oldTableProc = OS.SetWindowLong (handle, OS.GWL_WNDPROC, cast(int)TableProc); - oldHeaderProc = OS.SetWindowLong (hwndHeader, OS.GWL_WNDPROC, cast(int)HeaderProc); - } + oldTableProc = cast(WNDPROC)OS.SetWindowLongPtr (handle, OS.GWLP_WNDPROC, cast(LONG_PTR)TableProc); + oldHeaderProc = cast(WNDPROC)OS.SetWindowLongPtr (hwndHeader, OS.GWLP_WNDPROC, cast(LONG_PTR)HeaderProc); + } + + /* + * Feature in Windows. For some reason, when the table window + * proc processes WM_HSCROLL or WM_VSCROLL when there are many + * columns in the table, scrolling is slow and the table does + * not keep up with the position of the scroll bar. The fix + * is to turn off redraw, scroll, turn redraw back on and redraw + * the entire table. Strangly, redrawing the entire table is + * faster. + */ + bool fixScroll = false; + if (OS.LOWORD (wParam) !is OS.SB_ENDSCROLL) { + if (OS.COMCTL32_MAJOR >= 6) { + if (columnCount > H_SCROLL_LIMIT) { + int rowCount = OS.SendMessage (handle, OS.LVM_GETCOUNTPERPAGE, 0, 0); + if (rowCount > V_SCROLL_LIMIT) fixScroll = drawCount is 0 && OS.IsWindowVisible (handle); + } + } + } + if (fixScroll) OS.DefWindowProc (handle, OS.WM_SETREDRAW, 0, 0); LRESULT result = super.WM_HSCROLL (wParam, lParam); + if (fixScroll) { + OS.DefWindowProc (handle, OS.WM_SETREDRAW, 1, 0); + int flags = OS.RDW_ERASE | OS.RDW_FRAME | OS.RDW_INVALIDATE | OS.RDW_ALLCHILDREN; + OS.RedrawWindow (handle, null, null, flags); + /* + * Feature in Windows. On Vista only, it is faster to + * compute and answer the data for the visible columns + * of a table when scrolling, rather than just return + * the data for each column when asked. + */ + if (!OS.IsWinCE && OS.WIN32_VERSION >= OS.VERSION (6, 0)) { + RECT headerRect, rect; + OS.GetClientRect (handle, &rect); + bool [] visible = new bool [columnCount]; + for (int i=0; i<columnCount; i++) { + visible [i] = true; + if (OS.SendMessage (hwndHeader, OS.HDM_GETITEMRECT, i, &headerRect) !is 0) { + OS.MapWindowPoints (hwndHeader, handle, cast(POINT*)&headerRect, 2); + visible [i] = OS.IntersectRect(&headerRect, &rect, &headerRect) !is 0; + } + } + try { + display.hwndParent = OS.GetParent (handle); + display.columnVisible = visible; + OS.UpdateWindow (handle); + } finally { + display.columnVisible = null; + } + } + } + if (fixSubclass) { - OS.SetWindowLong (handle, OS.GWL_WNDPROC, oldTableProc); - OS.SetWindowLong (hwndHeader, OS.GWL_WNDPROC, oldHeaderProc); + OS.SetWindowLongPtr (handle, OS.GWLP_WNDPROC, cast(LONG_PTR)oldTableProc); + OS.SetWindowLongPtr (hwndHeader, OS.GWLP_WNDPROC, cast(LONG_PTR)oldHeaderProc); } /* @@ -5609,17 +6061,68 @@ * NOTE: The header tooltip can subclass the header proc so the * current proc must be restored or header tooltips stop working. */ - int oldHeaderProc = 0, oldTableProc = 0; + WNDPROC oldHeaderProc, oldTableProc; auto hwndHeader = cast(HWND) OS.SendMessage (handle, OS.LVM_GETHEADER, 0, 0); - bool fixSubclass = !hasChildren () && !hooks (DWT.Paint) && !filters (DWT.Paint); + bool fixSubclass = isOptimizedRedraw (); if (fixSubclass) { - oldTableProc = OS.SetWindowLong (handle, OS.GWL_WNDPROC, cast(int) TableProc); - oldHeaderProc = OS.SetWindowLong (hwndHeader, OS.GWL_WNDPROC, cast(int) HeaderProc); - } + oldTableProc = cast(WNDPROC)OS.SetWindowLongPtr (handle, OS.GWLP_WNDPROC, cast(LONG_PTR)TableProc); + oldHeaderProc = cast(WNDPROC)OS.SetWindowLongPtr (hwndHeader, OS.GWLP_WNDPROC, cast(LONG_PTR)HeaderProc); + } + + /* + * Feature in Windows. For some reason, when the table window + * proc processes WM_HSCROLL or WM_VSCROLL when there are many + * columns in the table, scrolling is slow and the table does + * not keep up with the position of the scroll bar. The fix + * is to turn off redraw, scroll, turn redraw back on and redraw + * the entire table. Strangly, redrawing the entire table is + * faster. + */ + bool fixScroll = false; + if (OS.LOWORD (wParam) !is OS.SB_ENDSCROLL) { + if (OS.COMCTL32_MAJOR >= 6) { + if (columnCount > H_SCROLL_LIMIT) { + int rowCount = OS.SendMessage (handle, OS.LVM_GETCOUNTPERPAGE, 0, 0); + if (rowCount > V_SCROLL_LIMIT) fixScroll = drawCount is 0 && OS.IsWindowVisible (handle); + } + } + } + if (fixScroll) OS.DefWindowProc (handle, OS.WM_SETREDRAW, 0, 0); LRESULT result = super.WM_VSCROLL (wParam, lParam); + if (fixScroll) { + OS.DefWindowProc (handle, OS.WM_SETREDRAW, 1, 0); + int flags = OS.RDW_ERASE | OS.RDW_FRAME | OS.RDW_INVALIDATE | OS.RDW_ALLCHILDREN; + OS.RedrawWindow (handle, null, null, flags); + /* + * Feature in Windows. On Vista only, it is faster to + * compute and answer the data for the visible columns + * of a table when scrolling, rather than just return + * the data for each column when asked. + */ + if (!OS.IsWinCE && OS.WIN32_VERSION >= OS.VERSION (6, 0)) { + RECT headerRect, rect; + OS.GetClientRect (handle, &rect); + bool [] visible = new bool [columnCount]; + for (int i=0; i<columnCount; i++) { + visible [i] = true; + if (OS.SendMessage (hwndHeader, OS.HDM_GETITEMRECT, i, &headerRect) !is 0) { + OS.MapWindowPoints (hwndHeader, handle, cast(POINT*)&headerRect, 2); + visible [i] = OS.IntersectRect(&headerRect, &rect, &headerRect) !is 0; + } + } + try { + display.hwndParent = OS.GetParent (handle); + display.columnVisible = visible; + OS.UpdateWindow (handle); + } finally { + display.columnVisible = null; + } + } + } + if (fixSubclass) { - OS.SetWindowLong (handle, OS.GWL_WNDPROC, oldTableProc); - OS.SetWindowLong (hwndHeader, OS.GWL_WNDPROC, oldHeaderProc); + OS.SetWindowLongPtr (handle, OS.GWLP_WNDPROC, cast(LONG_PTR)oldTableProc); + OS.SetWindowLongPtr (hwndHeader, OS.GWLP_WNDPROC, cast(LONG_PTR)oldHeaderProc); } /* @@ -5630,7 +6133,7 @@ */ int bits = OS.SendMessage (handle, OS.LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0); if ((bits & OS.LVS_EX_GRIDLINES) !is 0) { - int code = wParam & 0xFFFF; + int code = OS.LOWORD (wParam); switch (code) { case OS.SB_ENDSCROLL: case OS.SB_THUMBPOSITION: @@ -5646,9 +6149,9 @@ RECT clientRect; OS.GetClientRect (handle, &clientRect); clientRect.top += headerHeight; - int empty = OS.SendMessage (handle, OS.LVM_APPROXIMATEVIEWRECT, 0, 0); - int oneItem = OS.SendMessage (handle, OS.LVM_APPROXIMATEVIEWRECT, 1, 0); - int itemHeight = (oneItem >> 16) - (empty >> 16); + int /*long*/ empty = OS.SendMessage (handle, OS.LVM_APPROXIMATEVIEWRECT, 0, 0); + int /*long*/ oneItem = OS.SendMessage (handle, OS.LVM_APPROXIMATEVIEWRECT, 1, 0); + int itemHeight = OS.HIWORD (oneItem) - OS.HIWORD (empty); if (code is OS.SB_LINEDOWN) { clientRect.top = clientRect.bottom - itemHeight - GRID_WIDTH; } else { @@ -5670,9 +6173,9 @@ MEASUREITEMSTRUCT* struct_ = cast(MEASUREITEMSTRUCT*)lParam; //OS.MoveMemory (struct_, lParam, MEASUREITEMSTRUCT.sizeof); if (itemHeight is -1) { - int empty = OS.SendMessage (handle, OS.LVM_APPROXIMATEVIEWRECT, 0, 0); - int oneItem = OS.SendMessage (handle, OS.LVM_APPROXIMATEVIEWRECT, 1, 0); - struct_.itemHeight = (oneItem >> 16) - (empty >> 16); + int /*long*/ empty = OS.SendMessage (handle, OS.LVM_APPROXIMATEVIEWRECT, 0, 0); + int /*long*/ oneItem = OS.SendMessage (handle, OS.LVM_APPROXIMATEVIEWRECT, 1, 0); + struct_.itemHeight = OS.HIWORD (oneItem) - OS.HIWORD (empty); } else { struct_.itemHeight = itemHeight; } @@ -5681,196 +6184,17 @@ } override LRESULT wmNotify (NMHDR* hdr, int wParam, int lParam) { - auto hwndHeader = cast(HWND) OS.SendMessage (handle, OS.LVM_GETHEADER, 0, 0); + HWND hwndToolTip = cast(HWND) OS.SendMessage (handle, OS.LVM_GETTOOLTIPS, 0, 0); + if (hdr.hwndFrom is hwndToolTip) { + LRESULT result = wmNotifyToolTip (hdr, wParam, lParam); + if (result !is null) return result; + } + HWND hwndHeader = cast(HWND)OS.SendMessage (handle, OS.LVM_GETHEADER, 0, 0); if (hdr.hwndFrom is hwndHeader) { - /* - * Feature in Windows. On NT, the automatically created - * header control is created as a UNICODE window, not an - * ANSI window despite the fact that the parent is created - * as an ANSI window. This means that it sends UNICODE - * notification messages to the parent window on NT for - * no good reason. The data and size in the NMHEADER and - * HDITEM structs is identical between the platforms so no - * different message is actually necessary. Despite this, - * Windows sends different messages. The fix is to look - * for both messages, despite the platform. This works - * because only one will be sent on either platform, never - * both. - */ - switch (hdr.code) { - case OS.HDN_BEGINTRACKW: - case OS.HDN_BEGINTRACKA: - case OS.HDN_DIVIDERDBLCLICKW: - case OS.HDN_DIVIDERDBLCLICKA: { - if (columnCount is 0) return LRESULT.ONE; - NMHEADER* phdn = cast(NMHEADER*)lParam; - //OS.MoveMemory (phdn, lParam, NMHEADER.sizeof); - TableColumn column = columns [phdn.iItem]; - if (column !is null && !column.getResizable ()) { - return LRESULT.ONE; - } - ignoreColumnMove = true; - switch (hdr.code) { - case OS.HDN_DIVIDERDBLCLICKW: - case OS.HDN_DIVIDERDBLCLICKA: - /* - * Bug in Windows. When the first column of a table does not - * have an image and the user double clicks on the divider, - * Windows packs the column but does not take into account - * the empty space left for the image. The fix is to measure - * each items ourselves rather than letting Windows do it. - */ - bool fixPack = phdn.iItem is 0 && !firstColumnImage; - if (column !is null && (fixPack || hooks (DWT.MeasureItem))) { - column.pack (); - return LRESULT.ONE; - } - default: - } - break; - } - case OS.NM_RELEASEDCAPTURE: { - if (!ignoreColumnMove) { - for (int i=0; i<columnCount; i++) { - TableColumn column = columns [i]; - column.updateToolTip (i); - } - } - ignoreColumnMove = false; - break; - } - case OS.HDN_BEGINDRAG: { - if (ignoreColumnMove) return LRESULT.ONE; - int bits = OS.SendMessage (handle, OS.LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0); - if ((bits & OS.LVS_EX_HEADERDRAGDROP) is 0) break; - if (columnCount is 0) return LRESULT.ONE; - NMHEADER* phdn = cast(NMHEADER*)lParam; - //OS.MoveMemory (phdn, lParam, NMHEADER.sizeof); - if (phdn.iItem !is -1) { - TableColumn column = columns [phdn.iItem]; - if (column !is null && !column.getMoveable ()) { - ignoreColumnMove = true; - return LRESULT.ONE; - } - } - break; - } - case OS.HDN_ENDDRAG: { - int bits = OS.SendMessage (handle, OS.LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0); - if ((bits & OS.LVS_EX_HEADERDRAGDROP) is 0) break; - NMHEADER* phdn = cast(NMHEADER*)lParam; - //OS.MoveMemory (phdn, lParam, NMHEADER.sizeof); - if (phdn.iItem !is -1 && phdn.pitem !is null) { - HDITEM* pitem = cast(HDITEM*)phdn.pitem; - //OS.MoveMemory (pitem, phdn.pitem, HDITEM.sizeof); - if ((pitem.mask & OS.HDI_ORDER) !is 0 && pitem.iOrder !is -1) { - if (columnCount is 0) break; - int [] order = new int [columnCount]; - OS.SendMessage (handle, OS.LVM_GETCOLUMNORDERARRAY, columnCount, order.ptr); - int index = 0; - while (index < order.length) { - if (order [index] is phdn.iItem) break; - index++; - } - if (index is order.length) index = 0; - if (index is pitem.iOrder) break; - int start = Math.min (index, pitem.iOrder); - int end = Math.max (index, pitem.iOrder); - ignoreColumnMove = false; - for (int i=start; i<=end; i++) { - TableColumn column = columns [order [i]]; - if (!column.isDisposed ()) { - column.postEvent (DWT.Move); - } - } - } - } - break; - } - case OS.HDN_ITEMCHANGEDW: - case OS.HDN_ITEMCHANGEDA: { - /* - * Bug in Windows. When a table has the LVS_EX_GRIDLINES extended - * style and the user drags any column over the first column in the - * table, making the size become zero, when the user drags a column - * such that the size of the first column becomes non-zero, the grid - * lines are not redrawn. The fix is to detect the case and force - * a redraw of the first column. - */ - int width = OS.SendMessage (handle, OS.LVM_GETCOLUMNWIDTH, 0, 0); - if (lastWidth is 0 && width > 0) { - int bits = OS.SendMessage (handle, OS.LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0); - if ((bits & OS.LVS_EX_GRIDLINES) !is 0) { - RECT rect; - OS.GetClientRect (handle, &rect); - rect.right = rect.left + width; - OS.InvalidateRect (handle, &rect, true); - } - } - lastWidth = width; - if (!ignoreColumnResize) { - NMHEADER* phdn = cast(NMHEADER*)lParam; - //OS.MoveMemory (phdn, lParam, NMHEADER.sizeof); - if (phdn.pitem !is null) { - HDITEM* pitem = cast(HDITEM*)phdn.pitem; - //OS.MoveMemory (pitem, phdn.pitem, HDITEM.sizeof); - if ((pitem.mask & OS.HDI_WIDTH) !is 0) { - TableColumn column = columns [phdn.iItem]; - if (column !is null) { - column.updateToolTip (phdn.iItem); - column.sendEvent (DWT.Resize); - if (isDisposed ()) return LRESULT.ZERO; - /* - * It is possible (but unlikely), that application - * code could have disposed the column in the move - * event. If this happens, process the move event - * for those columns that have not been destroyed. - */ - TableColumn [] newColumns = new TableColumn [columnCount]; - System.arraycopy (columns, 0, newColumns, 0, columnCount); - int [] order = new int [columnCount]; - OS.SendMessage (handle, OS.LVM_GETCOLUMNORDERARRAY, columnCount, order.ptr); - bool moved = false; - for (int i=0; i<columnCount; i++) { - TableColumn nextColumn = newColumns [order [i]]; - if (moved && !nextColumn.isDisposed ()) { - nextColumn.updateToolTip (order [i]); - nextColumn.sendEvent (DWT.Move); - } - if (nextColumn is column) moved = true; - } - } - } - } - } - break; - } - case OS.HDN_ITEMDBLCLICKW: - case OS.HDN_ITEMDBLCLICKA: { - NMHEADER* phdn = cast(NMHEADER*)lParam; - //OS.MoveMemory (phdn, lParam, NMHEADER.sizeof); - TableColumn column = columns [phdn.iItem]; - if (column !is null) { - column.postEvent (DWT.DefaultSelection); - } - break; - } - default: - } - } - LRESULT result = super.wmNotify (hdr, wParam, lParam); - if (result !is null) return result; - switch (hdr.code) { - case OS.TTN_GETDISPINFOA: - case OS.TTN_GETDISPINFOW: { - tipRequested = true; - int code = callWindowProc (handle, OS.WM_NOTIFY, wParam, lParam); - tipRequested = false; - return new LRESULT (code); - } - default: - } - return result; + LRESULT result = wmNotifyHeader (hdr, wParam, lParam); + if (result !is null) return result; + } + return super.wmNotify (hdr, wParam, lParam); } override LRESULT wmNotifyChild (NMHDR* hdr, int wParam, int lParam) { @@ -5898,6 +6222,11 @@ NMLVDISPINFO* plvfi = cast(NMLVDISPINFO*)lParam; //OS.MoveMemory (plvfi, lParam, NMLVDISPINFO.sizeof); + bool [] visible = display.columnVisible; + if (visible !is null && !visible [plvfi.item.iSubItem]) { + break; + } + /* * When an item is being deleted from a virtual table, do not * allow the application to provide data for a new item that @@ -6056,16 +6385,19 @@ if (hooks (DWT.MouseDown) || hooks (DWT.MouseUp)) { return LRESULT.ONE; } + if ((style & DWT.RIGHT_TO_LEFT) !is 0) { + if (findImageControl () !is null) return LRESULT.ONE; + } break; } case OS.LVN_BEGINDRAG: case OS.LVN_BEGINRDRAG: { + if (OS.GetKeyState (OS.VK_LBUTTON) >= 0) break; dragStarted = true; if (hdr.code is OS.LVN_BEGINDRAG) { int pos = OS.GetMessagePos (); POINT pt; - pt.x = cast(short) (pos & 0xFFFF); - pt.y = cast(short) (pos >> 16); + OS.POINTSTOPOINT (pt, pos); OS.ScreenToClient (handle, &pt); sendDragEvent (1, pt.x, pt.y); } @@ -6092,6 +6424,11 @@ break; } case OS.LVN_ITEMCHANGED: { + if (fullRowSelect) { + fullRowSelect = false; + OS.DefWindowProc (handle, OS.WM_SETREDRAW, 1, 0); + OS.SendMessage (handle, OS.LVM_SETEXTENDEDLISTVIEWSTYLE, OS.LVS_EX_FULLROWSELECT, 0); + } if (!ignoreSelect) { NMLISTVIEW* pnmlv = cast(NMLISTVIEW*)lParam; //OS.MoveMemory (pnmlv, lParam, NMLISTVIEW.sizeof); @@ -6164,5 +6501,365 @@ return super.wmNotifyChild (hdr, wParam, lParam); } -} - +LRESULT wmNotifyHeader (NMHDR* hdr, int /*long*/ wParam, int /*long*/ lParam) { + /* + * Feature in Windows. On NT, the automatically created + * header control is created as a UNICODE window, not an + * ANSI window despite the fact that the parent is created + * as an ANSI window. This means that it sends UNICODE + * notification messages to the parent window on NT for + * no good reason. The data and size in the NMHEADER and + * HDITEM structs is identical between the platforms so no + * different message is actually necessary. Despite this, + * Windows sends different messages. The fix is to look + * for both messages, despite the platform. This works + * because only one will be sent on either platform, never + * both. + */ + switch (hdr.code) { + case OS.HDN_BEGINTRACKW: + case OS.HDN_BEGINTRACKA: + case OS.HDN_DIVIDERDBLCLICKW: + case OS.HDN_DIVIDERDBLCLICKA: { + if (columnCount is 0) return LRESULT.ONE; + NMHEADER* phdn = cast(NMHEADER*)lParam; + TableColumn column = columns [phdn.iItem]; + if (column !is null && !column.getResizable ()) { + return LRESULT.ONE; + } + ignoreColumnMove = true; + switch (hdr.code) { + case OS.HDN_DIVIDERDBLCLICKW: + case OS.HDN_DIVIDERDBLCLICKA: + /* + * Bug in Windows. When the first column of a table does not + * have an image and the user double clicks on the divider, + * Windows packs the column but does not take into account + * the empty space left for the image. The fix is to measure + * each items ourselves rather than letting Windows do it. + */ + bool fixPack = phdn.iItem is 0 && !firstColumnImage; + if (column !is null && (fixPack || hooks (DWT.MeasureItem))) { + column.pack (); + return LRESULT.ONE; + } + default: + } + break; + } + case OS.NM_RELEASEDCAPTURE: { + if (!ignoreColumnMove) { + for (int i=0; i<columnCount; i++) { + TableColumn column = columns [i]; + column.updateToolTip (i); + } + } + ignoreColumnMove = false; + break; + } + case OS.HDN_BEGINDRAG: { + if (ignoreColumnMove) return LRESULT.ONE; + int bits = OS.SendMessage (handle, OS.LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0); + if ((bits & OS.LVS_EX_HEADERDRAGDROP) is 0) break; + if (columnCount is 0) return LRESULT.ONE; + NMHEADER* phdn = cast(NMHEADER*)lParam; + if (phdn.iItem !is -1) { + TableColumn column = columns [phdn.iItem]; + if (column !is null && !column.getMoveable ()) { + ignoreColumnMove = true; + return LRESULT.ONE; + } + } + break; + } + case OS.HDN_ENDDRAG: { + int bits = OS.SendMessage (handle, OS.LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0); + if ((bits & OS.LVS_EX_HEADERDRAGDROP) is 0) break; + NMHEADER* phdn = cast(NMHEADER*)lParam; + if (cast(int)phdn.iItem !is -1 && cast(int)phdn.pitem !is 0) { + HDITEM* pitem = cast(HDITEM*)phdn.pitem; + if ((pitem.mask & OS.HDI_ORDER) !is 0 && pitem.iOrder !is -1) { + if (columnCount is 0) break; + int [] order = new int [columnCount]; + OS.SendMessage (handle, OS.LVM_GETCOLUMNORDERARRAY, columnCount, order.ptr); + int index = 0; + while (index < order.length) { + if (order [index] is phdn.iItem) break; + index++; + } + if (index is order.length) index = 0; + if (index is pitem.iOrder) break; + int start = Math.min (index, pitem.iOrder); + int end = Math.max (index, pitem.iOrder); + ignoreColumnMove = false; + for (int i=start; i<=end; i++) { + TableColumn column = columns [order [i]]; + if (!column.isDisposed ()) { + column.postEvent (DWT.Move); + } + } + } + } + break; + } + case OS.HDN_ITEMCHANGEDW: + case OS.HDN_ITEMCHANGEDA: { + /* + * Bug in Windows. When a table has the LVS_EX_GRIDLINES extended + * style and the user drags any column over the first column in the + * table, making the size become zero, when the user drags a column + * such that the size of the first column becomes non-zero, the grid + * lines are not redrawn. The fix is to detect the case and force + * a redraw of the first column. + */ + int width = OS.SendMessage (handle, OS.LVM_GETCOLUMNWIDTH, 0, 0); + if (lastWidth is 0 && width > 0) { + int bits = OS.SendMessage (handle, OS.LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0); + if ((bits & OS.LVS_EX_GRIDLINES) !is 0) { + RECT rect; + OS.GetClientRect (handle, &rect); + rect.right = rect.left + width; + OS.InvalidateRect (handle, &rect, true); + } + } + lastWidth = width; + if (!ignoreColumnResize) { + NMHEADER* phdn = cast(NMHEADER*)lParam; + if (phdn.pitem !is null) { + HDITEM* pitem = cast(HDITEM*)phdn.pitem; + if ((pitem.mask & OS.HDI_WIDTH) !is 0) { + TableColumn column = columns [phdn.iItem]; + if (column !is null) { + column.updateToolTip (phdn.iItem); + column.sendEvent (DWT.Resize); + if (isDisposed ()) return LRESULT.ZERO; + /* + * It is possible (but unlikely), that application + * code could have disposed the column in the move + * event. If this happens, process the move event + * for those columns that have not been destroyed. + */ + TableColumn [] newColumns = new TableColumn [columnCount]; + System.arraycopy (columns, 0, newColumns, 0, columnCount); + int [] order = new int [columnCount]; + OS.SendMessage (handle, OS.LVM_GETCOLUMNORDERARRAY, columnCount, order.ptr); + bool moved = false; + for (int i=0; i<columnCount; i++) { + TableColumn nextColumn = newColumns [order [i]]; + if (moved && !nextColumn.isDisposed ()) { + nextColumn.updateToolTip (order [i]); + nextColumn.sendEvent (DWT.Move); + } + if (nextColumn is column) moved = true; + } + } + } + } + } + break; + } + case OS.HDN_ITEMDBLCLICKW: + case OS.HDN_ITEMDBLCLICKA: { + NMHEADER* phdn = cast(NMHEADER*)lParam; + TableColumn column = columns [phdn.iItem]; + if (column !is null) { + column.postEvent (DWT.DefaultSelection); + } + break; + } + default: + } + return null; +} + +LRESULT wmNotifyToolTip (NMHDR* hdr, int /*long*/ wParam, int /*long*/ lParam) { + if (OS.IsWinCE) return null; + switch (hdr.code) { + case OS.NM_CUSTOMDRAW: { + if (toolTipText_ !is null) break; + if (isCustomToolTip ()) { + NMTTCUSTOMDRAW* nmcd = cast(NMTTCUSTOMDRAW*)lParam; + return wmNotifyToolTip (nmcd, lParam); + } + break; + } + case OS.TTN_GETDISPINFOA: + case OS.TTN_GETDISPINFOW: + case OS.TTN_SHOW: { + LRESULT result = super.wmNotify (hdr, wParam, lParam); + if (result !is null) return result; + if (hdr.code !is OS.TTN_SHOW) tipRequested = true; + int /*long*/ code = callWindowProc (handle, OS.WM_NOTIFY, wParam, lParam); + if (hdr.code !is OS.TTN_SHOW) tipRequested = false; + if (toolTipText_ !is null) break; + if (isCustomToolTip ()) { + LVHITTESTINFO pinfo; + int pos = OS.GetMessagePos (); + POINT pt; + OS.POINTSTOPOINT (pt, pos); + OS.ScreenToClient (handle, &pt); + pinfo.pt.x = pt.x; + pinfo.pt.y = pt.y; + if (OS.SendMessage (handle, OS.LVM_SUBITEMHITTEST, 0, &pinfo) !is -1) { + TableItem item = _getItem (pinfo.iItem); + auto hDC = OS.GetDC (handle); + HFONT oldFont, newFont = cast(HFONT)OS.SendMessage (handle, OS.WM_GETFONT, 0, 0); + if (newFont !is null) oldFont = OS.SelectObject (hDC, newFont); + auto hFont = item.fontHandle (pinfo.iSubItem); + if (cast(int)hFont !is -1) hFont = cast(HFONT)OS.SelectObject (hDC, hFont); + Event event = sendMeasureItemEvent (item, pinfo.iItem, pinfo.iSubItem, hDC); + if (!isDisposed () && !item.isDisposed ()) { + RECT itemRect; + OS.SetRect (&itemRect, event.x, event.y, event.x + event.width, event.y + event.height); + if (hdr.code is OS.TTN_SHOW) { + RECT* toolRect = toolTipRect (&itemRect); + OS.MapWindowPoints (handle, null, cast(POINT*)toolRect, 2); + auto hwndToolTip = cast(HWND) OS.SendMessage (handle, OS.LVM_GETTOOLTIPS, 0, 0); + int flags = OS.SWP_NOACTIVATE | OS.SWP_NOZORDER; + int width = toolRect.right - toolRect.left, height = toolRect.bottom - toolRect.top; + SetWindowPos (hwndToolTip, null, toolRect.left , toolRect.top, width, height, flags); + } else { + NMTTDISPINFO* lpnmtdi = null; + if (hdr.code is OS.TTN_GETDISPINFOA) { + lpnmtdi = cast(NMTTDISPINFO*)new NMTTDISPINFOA; + OS.MoveMemory (lpnmtdi, cast(void*) lParam, NMTTDISPINFOA.sizeof); + if (lpnmtdi.lpszText !is null) { + (cast(char*)lpnmtdi.lpszText)[0] = 0; + } + } else { + lpnmtdi = cast(NMTTDISPINFO*)new NMTTDISPINFOW; + OS.MoveMemory (lpnmtdi, cast(void*) lParam, NMTTDISPINFOW.sizeof); + if (lpnmtdi.lpszText !is null) { + (cast(wchar*)lpnmtdi.lpszText)[0] = 0; + } + } + RECT cellRect = item.getBounds (pinfo.iItem, pinfo.iSubItem, true, true, true, true, hDC); + if (itemRect.right > cellRect.right) { + //TEMPORARY CODE + String string = " "; +// String string = null; +// if (pinfo.iSubItem is 0) { +// string = item.text; +// } else { +// String [] strings = item.strings; +// if (strings !is null) string = strings [pinfo.iSubItem]; +// } + if (string !is null) { + Shell shell = getShell (); + wchar [] chars = StrToTCHARs(string, true ); + if (hdr.code is OS.TTN_GETDISPINFOA) { + char [] bytes = new char [chars.length * 2]; + OS.WideCharToMultiByte (getCodePage (), 0, chars.ptr, chars.length, bytes.ptr, bytes.length, null, null); + shell.setToolTipText (lpnmtdi, bytes); + OS.MoveMemory (lParam, cast(NMTTDISPINFOA*)lpnmtdi, NMTTDISPINFOA.sizeof); + } else { + shell.setToolTipText (lpnmtdi, chars); + OS.MoveMemory (lParam, cast(NMTTDISPINFOW*)lpnmtdi, NMTTDISPINFOW.sizeof); + } + } + } + } + } + if (hFont !is cast(HFONT)-1) hFont = OS.SelectObject (hDC, hFont); + if (newFont !is null) OS.SelectObject (hDC, oldFont); + OS.ReleaseDC (handle, hDC); + } + } + return new LRESULT (code); + } + } + return null; +} + +LRESULT wmNotifyToolTip (NMTTCUSTOMDRAW* nmcd, int /*long*/ lParam) { + if (OS.IsWinCE) return null; + switch (nmcd.nmcd.dwDrawStage) { + case OS.CDDS_PREPAINT: { + if (isCustomToolTip ()) { + //TEMPORARY CODE +// nmcd.uDrawFlags |= OS.DT_CALCRECT; +// OS.MoveMemory (lParam, nmcd, NMTTCUSTOMDRAW.sizeof); + return new LRESULT (OS.CDRF_NOTIFYPOSTPAINT | OS.CDRF_NEWFONT); + } + break; + } + case OS.CDDS_POSTPAINT: { + LVHITTESTINFO pinfo; + int pos = OS.GetMessagePos (); + POINT pt; + OS.POINTSTOPOINT (pt, pos); + OS.ScreenToClient (handle, &pt); + pinfo.pt.x = pt.x; + pinfo.pt.y = pt.y; + if (OS.SendMessage (handle, OS.LVM_SUBITEMHITTEST, 0, &pinfo) !is -1) { + TableItem item = _getItem (pinfo.iItem); + auto hDC = OS.GetDC (handle); + auto hFont = item.fontHandle (pinfo.iSubItem); + if (cast(int)hFont is -1) hFont = cast(HFONT)OS.SendMessage (handle, OS.WM_GETFONT, 0, 0); + auto oldFont = cast(HFONT)OS.SelectObject (hDC, hFont); + bool drawForeground = true; + RECT cellRect = item.getBounds (pinfo.iItem, pinfo.iSubItem, true, true, false, false, hDC); + if (hooks (DWT.EraseItem)) { + Event event = sendEraseItemEvent (item, nmcd, pinfo.iSubItem, &cellRect); + if (isDisposed () || item.isDisposed ()) break; + if (event.doit) { + drawForeground = (event.detail & DWT.FOREGROUND) !is 0; + } else { + drawForeground = false; + } + } + if (drawForeground) { + int nSavedDC = OS.SaveDC (nmcd.nmcd.hdc); + int gridWidth = getLinesVisible () ? Table.GRID_WIDTH : 0; + RECT* insetRect = toolTipInset (&cellRect); + OS.SetWindowOrgEx (nmcd.nmcd.hdc, insetRect.left, insetRect.top, null); + GCData data = new GCData (); + data.device = display; + data.foreground = OS.GetTextColor (nmcd.nmcd.hdc); + data.background = OS.GetBkColor (nmcd.nmcd.hdc); + data.font = Font.win32_new (display, hFont); + GC gc = GC.win32_new (nmcd.nmcd.hdc, data); + int x = cellRect.left; + if (pinfo.iSubItem !is 0) x -= gridWidth; + Image image = item.getImage (pinfo.iSubItem); + if (image !is null) { + Rectangle rect = image.getBounds (); + RECT imageRect = item.getBounds (pinfo.iItem, pinfo.iSubItem, false, true, false, false, hDC); + Point size = imageList is null ? new Point (rect.width, rect.height) : imageList.getImageSize (); + int y = imageRect.top; + if (!OS.IsWinCE && OS.WIN32_VERSION >= OS.VERSION (6, 0)) { + y = y + Math.max (0, (imageRect.bottom - imageRect.top - size.y) / 2); + } + gc.drawImage (image, rect.x, rect.y, rect.width, rect.height, x, y, size.x, size.y); + x += size.x + INSET + (pinfo.iSubItem is 0 ? -2 : 4); + } else { + x += INSET + 2; + } + String string = item.getText (pinfo.iSubItem); + if (string !is null) { + int flags = OS.DT_NOPREFIX | OS.DT_SINGLELINE | OS.DT_VCENTER; + TableColumn column = columns !is null ? columns [pinfo.iSubItem] : null; + if (column !is null) { + if ((column.style & DWT.CENTER) !is 0) flags |= OS.DT_CENTER; + if ((column.style & DWT.RIGHT) !is 0) flags |= OS.DT_RIGHT; + } + TCHAR[] buffer = StrToTCHARs (getCodePage (), string, false); + RECT textRect; + OS.SetRect (&textRect, x, cellRect.top, cellRect.right, cellRect.bottom); + OS.DrawText (nmcd.nmcd.hdc, buffer.ptr, buffer.length, &textRect, flags); + } + gc.dispose (); + OS.RestoreDC (nmcd.nmcd.hdc, nSavedDC); + } + if (hooks (DWT.PaintItem)) { + RECT itemRect = item.getBounds (pinfo.iItem, pinfo.iSubItem, true, true, false, false, hDC); + sendPaintItemEvent (item, nmcd, pinfo.iSubItem, &itemRect); + } + OS.SelectObject (hDC, oldFont); + OS.ReleaseDC (handle, hDC); + } + } + } + return null; +} +}